多线程和多处理时 fprintf 的行为如何?
Posted
技术标签:
【中文标题】多线程和多处理时 fprintf 的行为如何?【英文标题】:how fprintf behavior when multi-threaded and multi-processed? 【发布时间】:2020-07-31 00:35:03 【问题描述】:这里是进程a
和b
,它们都是多线程的。
a
forks b
和 b
立即执行一个新程序;
a
dup
s 和 freopen
s stderr 到日志文件(a
是事实上的 apache 的 httpd2.22)
b
从 a
继承打开的标准错误。 (我正在适配 apache httpd,b
是我的程序),b
使用 fprintf(stderr....)
进行日志记录
所以a
、b
共享同一个文件进行日志记录
a
、b
没有写日志的锁机制
我发现有些log msg是交错的,还有一点log msg丢失了。
同一文件的两个写入者可以隐式地相互锁定吗?
更重要的问题是:如果我们只在一个多线程进程中使用fprintf
,fprintf
是线程安全的,即fprintf
的一个调用不会干预另一个线程中的另一个fprintf
调用?很多文章都这么说,但是我自己也不容易保证,所以在这里求助。
A:复制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
然后
B:apache 它自己使用这种方式进行日志记录:
......
if (rv != APR_SUCCESS)
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s_main, ".........");
C:为了方便,我是这样登录的:
fprintf(stderr,".....\n")
我很确定 apache 和我使用相同的 fd 进行文件写入。
【问题讨论】:
最好贴出实际代码,而不是代码描述。 这是一个很长的程序,我的 fprintf 分散在各处。我会在 apache2 中找到将 stderr 复制到 error.log 的代码,然后将它们发布在这里 对不起,我的积分是不是因为这个原因被扣分了? 【参考方案1】:如果您使用单个FILE
对象在打开的文件上执行输出,那么整个fprintf
调用该FILE
将是原子的,即锁定在FILE
上的持续时间fprintf
电话。由于FILE
是单个进程地址空间的本地地址,因此这种设置仅适用于多线程应用程序;它不适用于多进程设置,其中多个不同进程正在访问引用同一底层打开文件的单独 FILE
对象。即使您在这里使用fprintf
,每个进程都有自己的FILE
,它可以锁定和解锁而其他人看不到更改,因此写入最终可能是交错的。有几种方法可以防止这种情况发生:
在共享内存中分配一个同步对象(例如进程共享的信号量或互斥锁),并使每个进程在写入文件之前获得锁(因此一次只能写入一个进程);或者
使用文件系统级别的咨询锁定,例如fcntl
锁定或(非 POSIX)BSD flock
接口;或者
不要直接写入日志文件,而是写入另一个进程将馈送到日志文件的管道。只要它们小于PIPE_BUF
字节长,就可以保证(通过 POSIX)对管道的写入是原子的。在这种情况下,您不能使用fprintf
(因为它可能执行多个底层写入操作),但您可以使用snprintf
到PIPE_BUF
大小的缓冲区,后跟write
。
【讨论】:
一个管道只能有一个写端和一个读端。所以,一个管道只能在2个进程之间使用。如果我设置了一个专用的日志进程,然后超过2个工作进程,这些工作进程中的每一个都必须创建一个管道,然后通过该管道将日志消息传递给日志记录进程。所以,这些管道是相互独立的,即使没有 POSIX 的保证,这些管道中的内容也不会被其他工作进程交错。日志进程有责任保证它从许多管道收到的 msgs 不被交错- ----------我说得对吗?tks 不,您可以为所有这些管道使用相同的管道。 tks,我会试试这个:将管道写入端的 fd 复制到多个进程,并且日志记录进程保持读取端。 在使用分叉 apache 设置时如何在 apache 模块中使用 ap_log_error()?日志会使用这个函数交错,还是这个函数可以防止这种情况发生? 选项 #3 毫无意义。如果您首先使用snprintf
在缓冲区中合成您的消息,您可以直接在O_APPEND
文件描述符上使用write
系统调用。不需要管道或其他协调过程。以上是关于多线程和多处理时 fprintf 的行为如何?的主要内容,如果未能解决你的问题,请参考以下文章