多线程和多处理时的fprintf行为如何?

时间:2012-07-26 07:29:08

标签: c linux printf

以下是流程ab,两者都是多线程的。

  1. a分叉bb立即执行一项新计划;
  2. a dup s和freopen s stderr到日志文件(a是defacto apache的httpd2.22)
  3. ba继承已打开的stderr。 (我正在调整apache httpd,b是我的程序),b使用fprintf(stderr....)进行记录
  4. 所以ab共享同一个记录文件
  5. ab没有锁定机制来写日志
  6. 我发现有些log msg是交错的,而且有一点log msg丢失了。

    同一个文件中的两个编写者是否可以隐式地互相锁定?

    更重要的问题是:如果我们仅在单个多线程进程中使用fprintffprintf是线程安全的,即fprintf的一次调用不会干预另一个fprintf ...... rv = apr_file_dup2(stderr_log, s_main->error_log, stderr_p);//dup the stderr to the logfile apr_file_close(s_main->error_log);//here ,2 fd point to the same file description,so close one of 在另一个线程中调用?很多文章都这么说,但这并不容易确保自己,所以我在这里寻求帮助。

    答:复制fd的代码是这样的:

    ......
    if (rv != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s_main, ".........");
    

    然后

    B:apache它自己用这种方式记录:

    fprintf(stderr,".....\n")
    

    C:为方便起见,我以这种方式登录:

    {{1}}

    我非常确定apache和我使用相同的fd进行文件编写。

1 个答案:

答案 0 :(得分:7)

如果您使用单个FILE对象在打开的文件上执行输出,那么对fprintf的{​​{1}}个调用将是原子的,即锁定在{在FILE电话的持续时间内{1}}。由于FILE是单个进程的地址空间的本地空间,因此只能在多线程应用程序中进行此设置。它不适用于多进程设置,其中几个不同的进程正在访问引用相同底层打开文件的单独fprintf对象。即使你在这里使用FILE,每个进程都有自己的FILE,它可以锁定和解锁,而其他进程看不到更改,因此写入最终会交错。有几种方法可以防止这种情况发生:

  1. 在共享内存中分配同步对象(例如进程共享信号量或互斥锁),并使每个进程在写入文件之前获取锁(因此一次只能写入一个进程); OR

  2. 使用文件系统级别的建议锁定,例如fprintf锁定或(非POSIX)BSD FILE接口; OR

  3. 不要直接写入日志文件,而是写入另一个进程将提供给日志文件的管道。只要它们小于fcntl字节长,保证(通过POSIX)对管道的写入是原子的。在这种情况下,您不能使用flock(因为它可能会执行多个底层写入操作),但您可以使用PIPE_BUFfprintf大小的缓冲区,后跟snprintf。< / p>