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;到 main 之外,以便它是一个全局变量。这样做并简单地运行./a.out会产生与前一种情况相同的预期输出,但是写入文件(例如 temp)现在会产生一个新的令人费解的行为:

Log opened.
Parent exiting.
Log opened.
Hello World!

写“日志已打开”的行。在之前,fork()所以我不明白为什么它应该在输出中出现两次。flush()(我什至在 the 之前放置了一个明确的内容fork(),以确保该输出行不只是被缓冲,然后缓冲区在 the 期间被复制fork(),后来两个副本最终都被刷新到流中......)所以这是谜题 #2。

当然,如果我注释掉整个fork()过程(标记为“步骤 2”的整个部分),那么它对于文件和stderr输出的行为都符合预期,无论logbuf是全局的还是本地的main()

此外,如果我切换filelog为 anofstream而不是stream_buffer<file_sink>(请参阅 中注释掉的行main()),那么它对于文件和stderr输出的行为也都符合预期,无论filelog/logbuf是全局的还是本地的main().

因此,这似乎是这些奇怪行为之间的相互作用file_sinkfork()产生了这些奇怪的行为......如果有人对可能导致这些行为的原因有任何想法,我将不胜感激!

4

1 回答 1

0

我想我已经弄清楚了……为后代/任何偶然发现这个问题寻找答案的人创建这个答案。

我在 boost 1.40 中观察到了这种行为,但是当我使用 boost 1.46 尝试它时,在所有情况下,一切都以预期的方式表现,即:

Log opened.
Parent exiting.
Hello World!

所以我现在的假设是,这实际上是 boost 中的一个错误,它在 1.41-1.46 版本之间的某个时间被修复。我在发行说明中没有看到任何让我很明显他们发现并修复了该错误的内容,但有可能发行说明讨论了修复此错误的一些根本原因,而我无法在两者之间建立联系根本原因和这种情况。

无论如何,解决方案似乎是安装 boost version >= 1.46

于 2013-07-24T19:02:47.880 回答