file_sink
(boost::iostreams で)を使用しfork()
てから子プロセスを使用すると、奇妙な動作が見られます。
exec()
これはプロセスのデーモン化の一部として行われるため、子は同じコードベースを継続します。つまり、呼び出しはありません。もちろん、私の完全なコードはプロセスを完全にデーモン化していますが、動作を再現するために不要な手順は省略しています。
次のコードは、動作を示す簡単な例です。
using namespace std;
namespace io = boost::iostreams;
void daemonize(std::ostream& log);
int main (int argc, char** argv)
{
io::stream_buffer<io::file_sink> logbuf;
std::ostream filelog(&logbuf);
//std::ofstream filelog;
// Step 1: open log
if (argc > 1)
{
//filelog.open(argv[1]);
logbuf.open(io::file_sink(argv[1]));
daemonize(filelog);
}
else
daemonize(std::cerr);
return EXIT_SUCCESS;
}
void daemonize(std::ostream& log)
{
log << "Log opened." << endl;
// Step 2: fork - parent stops, child continues
log.flush();
pid_t pid = fork(); // error checking omitted
if (pid > 0)
{
log << "Parent exiting." << endl;
exit(EXIT_SUCCESS);
}
assert(0 == pid); // child continues
// Step 3: write to log
sleep(1); // give parent process time to exit
log << "Hello World!" << endl;
}
これを引数なしで実行すると (例: ./a.out
)、ログが に記録されstderr
、期待される出力が得られます。
Log opened.
Parent exiting.
Hello World!
ただし、次のようなことをすると、次のよう./a.out temp; sleep 2; cat temp
になります。
Log opened.
Hello World!
そのため、親はどういうわけかフォーク後にファイルに書き込んでいません。それがパズル #1 です。
io::stream_buffer<io::file_sink> logbuf;
ここで、グローバル変数になるようにメインの外に移動したとします。それを実行して単純に実行./a.out
すると、前の場合と同じ期待される出力が得られますが、ファイル (たとえば、temp) に書き込むと、新しい不可解な動作が発生します。
Log opened.
Parent exiting.
Log opened.
Hello World!
「ログを開いた」と書かれている行。の前にあるfork()
ので、出力に 2 回表示される理由がわかりません。(出力行が単純にバッファリングされていないことを確認するために、前に明示的なflush()
直後を配置し、その後、両方のコピーが最終的にストリームにフラッシュされたときにバッファがコピーされました...) これがパズル #2 です。fork()
fork()
もちろん、fork()
プロセス全体 (「ステップ 2」とラベル付けされたセクション全体) をコメントアウトすると、ファイルとstderr
出力の両方で期待どおりに動作し、logbuf
グローバルかローカルかに関係なく動作しますmain()
。
また、代わりにに切り替えるfilelog
と( のコメントアウトされた行を参照)、ファイルと出力の両方で期待どおりに動作し、 /がグローバルかローカルかに関係なく動作します。ofstream
stream_buffer<file_sink>
main()
stderr
filelog
logbuf
main()
file_sink
したがって、これらの奇妙な動作との間の相互作用であるように思われfork()
ます...これらの原因について誰かがアイデアを持っている場合は、助けていただければ幸いです!