Boost: how to create a thread so that you can control all of its standard output, standard errors?

北慕城南 提交于 2020-01-04 06:50:18

问题


I create a win32 console app in C++. I use some API (not mine, and I can not modify its sources). It Is written so that it writes some of its info onto console screen not asking... each time I call it (48 times per second) So I want to put it into some thread and limit its output capabilities, but I need to get notified when that thread will try to output some message which is important for me. I have message text in standard string. How to do such thing in C++ using boost?


回答1:


That feature does not exist in Boost. You can, however, use _dup2 to replace the standard out descriptor:

#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <io.h>
#include <iostream>
#include <windows.h>

int main()
{
    HANDLE h = CreateFile(TEXT("test.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (0 == SetStdHandle(STD_OUTPUT_HANDLE, h)) {
        std::fprintf(stderr, "`SetStdHandle` failed with error %d\n", (int)GetLastError());
        return EXIT_FAILURE;
    }

    int h_desc = _open_osfhandle((long)h, 0);
    _dup2(h_desc, STDOUT_FILENO);

    std::printf("test\r\n"); // This actually writes to `h`.
    std::fflush(stdout);

    std::cout << "another test" << std::endl; // Also writes to `h`

    CloseHandle(h);
    return EXIT_SUCCESS;
}

Essentially what this trick does is allow you to redirect all writes to stdout, std::cout, and GetStdHandle(STD_OUTPUT_HANDLE) to a writable handle of your choosing (h). Of course, you can use CreatePipe to create the writable handle (h) and read from the readable end in another thread.

EDIT: If you are looking for a cross-platform solution, note that this trick is even easier on POSIX-compatible systems because dup2 is a standard function in unistd.h and "writable handles" are already descriptors.




回答2:


Here's a crazy idea:

If the lib is using cout/cerr, you could replace the streambuf of these global variables with an implementation of your own. It would, on flush/data, check some thread-local variable to see if the data came from the thread that calls the library, then route it somewhere else (i.e. into a std::string/std::ostringstream) instead of to the regular cout/cerr streambufs. (Which you should keep around.)

If it's using c's stdout/stderr, I think it'd be harder to do properly, but it might be doable still. You'd need to create some pipes and route stuff back and forth. More of a C/unixy question then, which I don't know that much about... yet. :)

Hope it helps.




回答3:


I cannot think of a way to achieve in Boost what you want, as the problem is described.

However, this API behaviour is very perplexing. Spitting out reams of output to the console is a bit antisocial. Are you using a Debug build of the API library? Are you sure there's no way to configure the API such that it outputs this data to a different stream, so that you can filter it without capturing the entire standard output? Is there a way to reduce the amount of output, so that you only see the important events you care about?

If you really need to capture standard output and act on certain strings (events) of interest, then Win32 provides ways to do this, but I'd really take a hard look at whether this output can be modified to meet your needs before resorting to that.



来源:https://stackoverflow.com/questions/4278969/boost-how-to-create-a-thread-so-that-you-can-control-all-of-its-standard-output

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!