开发者

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

开发者 https://www.devze.com 2023-01-26 18:29 出处:网络
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

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?


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.


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号