0

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と( のコメントアウトされた行を参照)、ファイルと出力の両方で期待どおりに動作し、 /がグローバルかローカルかに関係なく動作します。ofstreamstream_buffer<file_sink>main()stderrfileloglogbufmain()

file_sinkしたがって、これらの奇妙な動作との間の相互作用であるように思われfork()ます...これらの原因について誰かがアイデアを持っている場合は、助けていただければ幸いです!

4

1 に答える 1

0

私はそれを理解したと思います...後世/答えを探してこの質問に出くわした人のためにこの答えを作成します。

ブースト 1.40 でこの動作を観察しましたが、ブースト 1.46 を使用して試してみると、すべての場合ですべてが期待どおりに動作しました。

Log opened.
Parent exiting.
Hello World!

したがって、これは実際にはブーストのバグであり、バージョン 1.41 から 1.46 の間に修正されたものであると私は推測しています。リリース ノートには、バグを見つけて修正したことを明らかにするものは何もありませんでしたが、リリース ノートでこのバグの根本的な原因の修正について説明されていた可能性があります。その根本的な原因とこのシナリオ。

いずれにせよ、解決策はブーストバージョン> = 1.46をインストールすることのようです

于 2013-07-24T19:02:47.880 に答える