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

bas*_*bie 2 c linux printf

下面是过程ab,这两者都是多线程的.

  1. a叉子bb立即执行一个新程序;
  2. a dups和freopens stderr到日志文件(a是defacto apache的httpd2.22)
  3. b继承了打开的stderr a.(我适应apache httpd的,b是我的程序),并b使用fprintf(stderr....)了日志记录
  4. 所以a,b共享同一个文件进行日志记录
  5. 没有锁机制a,b写日志

我发现一些log msg是交错的,并且有一点log msg丢失了.

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

更重要的问题是:如果我们fprintf只在一个单线程中使用多线程进程,那么fprintf线程是否安全,即一次调用fprintf不会干扰fprintf另一个线程中的另一个调用?很多文章都这么说,但这并不容易确保自己,所以我在这里寻求帮助.

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

......
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 
Run Code Online (Sandbox Code Playgroud)

然后

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

......
if (rv != APR_SUCCESS) {
    ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s_main, ".........");
Run Code Online (Sandbox Code Playgroud)

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

fprintf(stderr,".....\n")
Run Code Online (Sandbox Code Playgroud)

我很确定apache和我使用相同的fd进行文件编写.

R..*_*R.. 7

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

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

  2. 使用文件系统级顾问锁定,例如fcntl锁或(非POSIX)BSD flock接口; 要么

  3. 而不是直接写入日志文件,写入另一个进程将提供给日志文件的管道.只要长度小于PIPE_BUF字节,保证(通过POSIX)对管道的写入是原子的.fprintf在这种情况下你不能使用(因为它可能执行多个底层写操作),但你可以使用后跟snprintfPIPE_BUF-sized缓冲区write.