У меня есть программа, которая порождает поток писателя с UNIX fork()
. Это прекрасно работает, но когда буферизованный поток C++ еще не очищен, я получаю условие гонки, когда два потока выводят одни и те же данные. Следующий пример показывает, что я имею в виду:Состояние гонки буферизованных потоков C++ при вызове fork-force flush?
extern "C" {
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
}
#define W 10
#include <iostream>
int main(void)
{
pid_t pid;
int status;
for (int i = 0; i < (1 << W); i++) {
// spawn a child after adding to the std::cout buffer
if (i == (1 << (W - 1))) {
// std::cout.flush(); // (1)
pid = fork();
if (!pid)
break;
}
// join the child thread after a while
if (i == 3 * (1 << (W - 2)))
waitpid(pid, &status, 0);
// print stuff to the stream
std::cout << i << '\n';
// std::cout << i << std::endl; // (2)
}
return EXIT_SUCCESS;
}
Так обходной путь я попытался являются (1) вровень std::cout
вручную прямо перед вызовом fork()
(предпочтительное решение), или (2) с использованием std::endl
при записи потока, но это добавляет излишне много звонков flush
. Хотя этот вид работ для std::cout
, который доступен по всему миру, мое предпочтительное решение (1) не работает для других буферизованных потоков, которые не доступны по всему миру. Кроме того, в какой-то момент я мог бы открыть еще один файл, и я, вероятно, забыл бы его сбросить.
Есть ли лучшее решение этой проблемы? Как функция, которую сбрасывает все буферизированный C++ streams?
РЕДАКТИРОВАТЬ
Предлагаемым решения заключается в использовании fflush(nullptr)
из библиотеки C, чтобы смыть все (C) потоки. Это работает для std::cout
и std::cerr
, которые хранятся в синхронизации с stdout
и stderr
, но другие буферизованные потоки С ++ будут не быть синхронизированы. Это демонстрирует проблему:
extern "C" {
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
}
#include <iostream>
#include <fstream>
#define W 10
int main(void)
{
pid_t pid;
int status;
std::ofstream fout("foo");
for (int i = 0; i < (1 << W); i++) {
if (i == (1 << (W - 1))) {
fflush(nullptr); // this works for std::{cout,cerr} but not files
pid = fork();
if (!pid)
return EXIT_SUCCESS;
}
if (i == 3 * (1 << (W - 2)))
waitpid(pid, &status, 0);
fout << i << '\n';
std::cout << i << '\n';
}
fout.close();
return EXIT_SUCCESS;
}
В моей системе я получаю
$ ./a.out 1>bar; wc -l foo bar
1536 foo
1024 bar
Излишне говорить о том, что число строк должно быть одинаковым.
Другие идеи?
хорошо .. не C++ буферизованные потоки и C буферизированные потоки две разные вещи? Тогда функция C, скорее всего, будет только скрывать потоки C. – user1978011
На самом деле, я думаю, вы правы. Хотя это гарантированно работает для стандартных потоков вывода и ошибок (потоки C++ и C синхронизируются), я не уверен, что происходит для других файловых потоков. –
Я думаю, что до тех пор, как 'sync_with_stdio (true);' для стандартных потоков, тогда вы в порядке (поскольку они будут использовать одни и те же буферы). Но я не думаю, что другие открытые потоки будут размыты. – vsoftco