use*_*743 16 c linux printf multithreading multiprocess
我正在实现一个使用不同内核的多线程程序,并且同时执行许多线程.每个线程都进行一次printf()调用,结果不可读.
我如何制作printf()原子,以便printf()一个线程中的printf()调用与另一个线程中的调用不冲突?
Jon*_*ler 19
POSIX规范包括以下功能:
getc_unlocked()getchar_unlocked()putc_unlocked()putchar_unlock()功能版本
getc(),getchar(),putc(),并putchar()分别命名为getc_unlocked(),getchar_unlocked(),putc_unlocked(),并putchar_unlocked()应提供在功能上等同于原始版本,与他们就不需要在一个线程安全的方式来实现的例外.在flockfile()(或ftrylockfile())和受保护的范围内使用时,它们应是线程安全的funlockfile().当且仅当在调用线程拥有(FILE *)对象时调用它们时,这些函数可以安全地用在多线程程序中,就像成功调用flockfile()或ftrylockfile()函数之后的情况一样.
这些功能的规范提到:
flockfile()ftrylockfile()funlockfile()flockfile()et al 的规范包括一揽子要求:
引用(
FILE *)对象的所有函数(名称_unlocked以其结尾的函数除外)的行为应该像在内部使用flockfile()并在funlockfile()内部获取这些(FILE *)对象的所有权一样.
这取代了此答案以前版本中的建议代码.POSIX标准还规定:
[
*lockfile()]函数的行为就像存在与每个(FILE *)对象关联的锁定计数一样.FILE *创建()对象时,此计数隐式初始化为零.FILE *当计数为零时,()对象被解锁.当计数为正时,单个线程拥有(FILE *)对象.flockfile()调用该函数时,如果计数为零或计数为正且调用者拥有(FILE *)对象,则计数应递增.否则,调用线程将被挂起,等待计数返回零.每次呼叫funlockfile()都应减少计数.这允许匹配调用flockfile()(或成功调用ftrylockfile())并funlockfile()嵌套.
还有字符I/O功能的规范:
格式化的输出函数在此处记录:
printf()规范中的一个关键条款是:
生成
fprintf()和printf()打印的字符就像fputc()被调用一样.
注意使用'似乎'.但是,每个printf()函数都需要应用锁,以便在多线程应用程序中控制对流的访问.一次只有一个线程可以使用给定的文件流.如果操作是用户级调用fputc(),则其他线程可以散布输出.如果操作是用户级调用,例如printf(),那么整个调用和对文件流的所有访问都得到有效保护,因此只有一个线程正在使用它,直到调用printf()返回.
在关于线程主题的POSIX的系统接口:一般信息部分中,它说:
2.9.1线程安全
本卷POSIX.1-2008定义的所有函数都应是线程安全的,但以下函数1不必是线程安全的.
...一系列不需要线程安全的函数...
...在
getc_unlocked(),getchar_unlocked(),putc_unlocked(),和putchar_unlocked()除非调用线程拥有(功能不需要是线程安全FILE *的调用访问)对象,是一个成功的调用后的情况flockfile()或ftrylockfile()功能.实现应根据需要提供内部同步,以满足此要求.
豁免职能清单不包含fputc或putc或putchar(或printf()等).
改写2017-07-26.
printf()概念上调用,这意味着POSIX定义的流输出函数在每次调用时也是线程安全的.flockfile()funlockfile()flockfile(),并funlockfile()在相关的流(不带系统的使用干扰*lockfile()功能.这意味着不需要为自己创建互斥或等效机制; 该实现提供了允许您printf()在多线程应用程序中控制对等人的访问的功能.
...之前的答案中的代码已删除,因为不再相关......
Gra*_*sus 15
为了不混合来自不同线程的输出,您需要确保一次只使用一个线程printf.要实现这一点,最简单的解决方案是使用a mutex.在开始时初始化mutex:
static pthread_mutex_t printf_mutex;
...
int main()
{
...
pthread_mutex_init(&printf_mutex, NULL);
...
Run Code Online (Sandbox Code Playgroud)
然后创建一个包装器printf以确保只有获得mutex可以调用的线程printf(否则它将被阻塞直到mutex可用):
int sync_printf(const char *format, ...)
{
va_list args;
va_start(args, format);
pthread_mutex_lock(&printf_mutex);
vprintf(format, args);
pthread_mutex_unlock(&printf_mutex);
va_end(args);
}
Run Code Online (Sandbox Code Playgroud)