Boost: как создать поток, чтобы вы могли контролировать все его стандартные выходные, стандартные ошибки? - PullRequest
2 голосов
/ 25 ноября 2010

Я создаю консольное приложение win32 на C ++. Я использую некоторый API (не мой, и я не могу изменить его источники). Он написан так, что он записывает часть своей информации на экран консоли, не спрашивая ... каждый раз, когда я вызываю его (48 раз в секунду), поэтому я хочу поместить его в какой-то поток и ограничить его возможности вывода, но мне нужно уведомление, когда этот поток попытается вывести какое-то сообщение, которое важно для меня. У меня есть текст сообщения в стандартной строке. Как сделать это в C ++, используя boost?

Ответы [ 3 ]

2 голосов
/ 25 ноября 2010

Вот сумасшедшая идея:

Если в lib используется cout / cerr, вы можете заменить streambuf этих глобальных переменных своей собственной реализацией.В flush / data он проверит некоторую локальную переменную потока, чтобы увидеть, пришли ли данные из потока, который вызывает библиотеку, а затем направит их куда-то еще (т.е. в std :: string / std :: ostringstream) вместообычный cout / cerr streambufs.(Который вы должны держать под рукой.)

Если он использует c's stdout / stderr, я думаю, что это будет сложнее сделать правильно, но это может быть выполнимо до сих пор.Вам нужно будет создать несколько каналов и проложить маршрут туда и обратно.Больше вопросов о C / unixy тогда, о которых я не знаю так много ... пока.:)

Надеюсь, это поможет.

1 голос
/ 26 ноября 2010

Эта функция не существует в Boost.Однако вы можете использовать _dup2 для замены стандартного дескриптора out:

#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;
}

По сути, этот трюк позволяет перенаправлять все записи в stdout, std::cout и GetStdHandle(STD_OUTPUT_HANDLE) на записываемую ручку по вашему выбору (h).Конечно, вы можете использовать CreatePipe, чтобы создать доступный для записи дескриптор (h) и читать с читаемого конца в другом потоке.

EDIT: Есливы ищете кроссплатформенное решение, обратите внимание, что этот прием еще проще в POSIX-совместимых системах, потому что dup2 - стандартная функция в unistd.h, а «записываемые дескрипторы» - уже дескрипторы.1023 *

1 голос
/ 25 ноября 2010

Я не могу придумать способ добиться в Boost того, чего вы хотите, поскольку проблема описана.

Однако такое поведение API очень озадачивает.Выплевывание пакетов вывода на консоль немного асоциально.Используете ли вы Debug сборку библиотеки API?Вы уверены, что нет способа настроить API так, чтобы он выводил эти данные в другой поток, чтобы можно было отфильтровать его, не захватывая весь стандартный вывод?Есть ли способ уменьшить объем вывода, чтобы вы могли видеть только важные события, которые вас интересуют?

Если вам действительно нужно захватить стандартный вывод и воздействовать на определенные интересующие строки (события), тогда Win32предоставляет способы сделать это, но я бы действительно внимательно рассмотрел вопрос о том, можно ли изменить этот вывод в соответствии с вашими потребностями, прежде чем прибегать к этому.

...