【问题标题】:Strange behavior with boost file_sink when forking分叉时 boost file_sink 的奇怪行为
【发布时间】:2013-07-23 00:42:49
【问题描述】:

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

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

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

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

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

所以看起来确实是file_sinkfork() 之间的交互产生了这些奇怪的行为......如果有人对可能导致这些问题的原因有任何想法,我将不胜感激!

【问题讨论】:

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


    【解决方案1】:

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

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

    Log opened.
    Parent exiting.
    Hello World!
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-17
      • 1970-01-01
      • 2014-07-11
      • 2022-09-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多