stdout线程安全在Linux上的C?
在Linux上使用printf
线程安全写入标准输出? 那么使用底层write
命令呢?
它不是由C标准规定的 – 它取决于你的C标准库的实现。 事实上,C标准甚至没有提到线程,因为某些系统(如embedded式系统)没有multithreading。
在GNU实现( glibc
)中,处理FILE*
对象的stdio中的大多数高级函数都是线程安全的。 那些通常不会unlocked
的名称(例如getc_unlocked(3)
)。 但是,线程的安全性在每个函数的调用级别上:例如,如果您对printf(3)
进行多个调用,那么每个调用都保证以primefaces方式输出,但其他线程可能会在调用printf()
。 如果要确保一系列I / O调用以primefaces方式输出,可以用一对flockfile(3)/funlockfile(3)
调用来lockingFILE
句柄。 请注意,这些函数是可重入的,因此您可以在它们之间安全地调用printf()
,即使printf()
本身调用flockfile()
,也不会导致死锁。
write(2)
等底层的I / O调用应该是线程安全的,但是我不是100%确定的, write()
会调用内核来执行I / O操作。 这个怎么发生取决于你正在使用的内核。 它可能是sysenter
指令,或者旧系统上的int
(中断)指令。 一旦进入内核,就要由内核来确保I / O是线程安全的。 在一个testing中,我只是用Darwin Kernel Version 8.11.1做的, write(2)
似乎是线程安全的。
是否将其称为“线程安全”取决于您对线程安全的定义。 POSIX需要使用stdio
函数来使用locking,所以如果从多个线程同时使用printf
,程序不会崩溃,损坏FILE
对象状态等。 然而,所有 stdio
操作都是通过重复调用fgetc
和fputc
来正式指定的,所以没有大规模的primefaces性保证。也就是说,如果线程1和2同时尝试打印 "Hello\n"
和"Goodbye\n"
,则不能保证输出将是"Hello\nGoodbye\n"
"Goodbye\nHello\n"
"Hello\nGoodbye\n"
或"Goodbye\nHello\n"
"Hello\nGoodbye\n"
"Goodbye\nHello\n"
。它也可以是 "HGelolodboy\ne\n"
。在实践中,大多数实现会为整个更高级别的写入调用获取一个锁,因为它更高效,但是您的程序不应该这样做。 可能会有angular落的情况下,这没有完成; 例如一个实现可能完全忽略locking未缓冲的stream。
编辑:关于primefaces性的上述文本是不正确的。 POSIX保证所有的stdio
操作都是primefaces操作,但是flockfile
的文档中隐藏了保证: http : flockfile
引用(FILE *)对象的所有函数的行为就像在内部使用flockfile()和funlockfile()来获得这些(FILE *)对象的所有权一样。
您可以自己使用flockfile
, ftrylockfile
和funlockfile
函数来实现大于单一函数调用的primefaces写入。
它们都是线程安全的,以至于如果多个线程在相同的文件描述符上调用它们,应用程序不会崩溃。 但是,如果没有一些应用程序级别的locking,则可以将任何写入的内容交错。
这是线程安全的; printf应该是可重入的,并且不会在程序中造成任何奇怪或损坏。
你不能保证你从一个线程的输出不会从另一个线程的输出中途开始。 如果你关心的是,你需要开发自己的locking输出代码,以防止多重访问。
自从这个问题被问及(最后回答)以来,C得到了一个新的标准。
C11现在提供了multithreading支持,并解决了stream的multithreading行为:
§7.21.2stream
每个stream都有一个关联的锁,当多个执行线程访问一个stream时,用来防止数据 竞争 ,并限制多个线程执行的stream操作的交错 。 一次只能有一个线程持有这个锁。 锁是可重入的:单个线程可以在给定的时间多次保持锁。
所有读取,写入,定位或查询stream位置的函数在访问stream之前lockingstream。 访问完成后,它们释放与stream关联的锁。
所以,使用C11线程的实现必须保证使用printf
是线程安全的。
是否保证了primefaces性(如无交织1 )是一目了然的,因为这个标准谈到了限制交织,而不是防止 ,它是数据竞赛所要求的。
我倾向于保证。 该标准提到了限制交织,因为一些不改变结果的交织仍然被允许发生; 例如, fwrite
一些字节,然后再fseek
一些字节,直到原始的偏移量,这样两个fwrite
就是背靠背的。 这个实现可以自由地对这两个fwrite
进行重新sorting,并将它们合并成一个单独的写入。
1 :以R ..的答案为例。