以下是流程a
和b
,两者都是多线程的。
a
分叉b
和b
立即执行一项新计划; a
dup
s和freopen
s stderr到日志文件(a
是defacto apache的httpd2.22)b
从a
继承已打开的stderr。 (我正在调整apache httpd,b
是我的程序),b
使用fprintf(stderr....)
进行记录a
,b
共享同一个记录文件a
,b
没有锁定机制来写日志我发现有些log msg是交错的,而且有一点log msg丢失了。
同一个文件中的两个编写者是否可以隐式地互相锁定?
更重要的问题是:如果我们仅在单个多线程进程中使用fprintf
,fprintf
是线程安全的,即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进行文件编写。
答案 0 :(得分:7)
如果您使用单个FILE
对象在打开的文件上执行输出,那么对fprintf
的{{1}}个调用将是原子的,即锁定在{在FILE
电话的持续时间内{1}}。由于FILE
是单个进程的地址空间的本地空间,因此只能在多线程应用程序中进行此设置。它不适用于多进程设置,其中几个不同的进程正在访问引用相同底层打开文件的单独fprintf
对象。即使你在这里使用FILE
,每个进程都有自己的FILE
,它可以锁定和解锁,而其他进程看不到更改,因此写入最终会交错。有几种方法可以防止这种情况发生:
在共享内存中分配同步对象(例如进程共享信号量或互斥锁),并使每个进程在写入文件之前获取锁(因此一次只能写入一个进程); OR
使用文件系统级别的建议锁定,例如fprintf
锁定或(非POSIX)BSD FILE
接口; OR
不要直接写入日志文件,而是写入另一个进程将提供给日志文件的管道。只要它们小于fcntl
字节长,保证(通过POSIX)对管道的写入是原子的。在这种情况下,您不能使用flock
(因为它可能会执行多个底层写入操作),但您可以使用PIPE_BUF
到fprintf
大小的缓冲区,后跟snprintf
。< / p>