I have a program that spawns a writer thread with UNIX fork()
. This works fine, but when a buffered C++ stream has not been flushed yet, I get a race condition where two threads output the same data. The following example shows what I mean:
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;
}
So the workaround I tried are to (1) flush std::cout
by hand right before calling fork()
(preferred solution), or (2) using std::endl
when writing to the stream, but this adds unnecessarily many flush
calls. Although this kind of works for std::cout
which is globally accessible, my preferred solution (1) does not work for other buffered streams that are not globally accessible. Besides, at some point I might open another file and I would probably forget to flush it then.
Is there a better solution to this problem? Like a function that flushes all buffered C++ streams ?
EDIT
A suggested solution was to use fflush(nullptr)
from the C library to flush all (C) streams. This works for std::cout
and std::cerr
which are kept in sync with stdout
and stderr
, but other C++ buffered streams will not be synced. This demonstrates the problem:
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;
}
On my system I get
$ ./a.out 1>bar; wc -l foo bar
1536 foo
1024 bar
Needless to say that the number of lines should be equal.
Any further ideas?
Use fflush
, and pass it nullptr
.
From the man:
#include <cstdio> // adapted the include for C++
int fflush(FILE *stream);
If the stream argument is NULL, fflush() flushes all open output streams.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.