分叉时使用boost file_sink的奇怪行为

时间:2013-07-23 00:42:50

标签: c++ boost file-io process fork

当我使用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!

因此父母不知何故在fork之后不再写入文件。那是谜题#1。

现在假设我只是将io::stream_buffer<io::file_sink> logbuf;移到main之外,这样它就是一个全局变量。这样做只需运行./a.out就可以得到与前一种情况相同的预期输出,但写入文件(例如,temp)现在会产生一种新的令人费解的行为:

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

写入“Log open”的行。在fork()之前,所以我不明白为什么它应该在输出中出现两次。 (我甚至在flush()之前立即显式fork()以确保输出行不是简单缓冲,然后在fork()期间复制缓冲区,最后两个副本最终复制冲到溪流......)这就是#2的谜题。

当然,如果我注释掉整个fork()进程(标记为“步骤2”的整个部分),那么它对文件和stderr输出的行为都是预期的,无论是否{ {1}}是logbuf的全球或本地。

另外,如果我将main()切换为filelog而不是ofstream(请参阅stream_buffer<file_sink>中注释掉的行),那么它的行为与文件和main()输出,无论stderr / filelog是全局还是本地logbuf

所以看来这是main()file_sink之间的互动,产生了这些奇怪的行为......如果有人对可能导致这些行为的想法有所了解,我会很感激帮助!

1 个答案:

答案 0 :(得分:0)

我想我已经明白了......为后代创造这个答案/任何偶然发现这个问题寻找答案的人。

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

Log opened.
Parent exiting.
Hello World!

所以我现在的假设是,这实际上是版本1.41-1.46之间修复的增强中的错误。我没有在发行说明中看到任何内容,这让我发现他们发现&amp;修复了这个bug,但是发布说明可能会解决这个bug的一些根本原因并且我无法在这个底层原因和这个场景之间建立连接。

无论如何,解决方案似乎是安装boost版本&gt; = 1.46