fprintf 命令的单行代码是线程安全的吗?

5

我正在使用OpenMP,我的程序如下所示:

\#pragma omp parallel for

for(x = 0, y = 0, x < 5, x++, y++)

     function(x, y, fp);

void function(int x , int y, FILE* fp);
{
   fprintf(fp, "(%d, %d)\n", x y);
}

我希望您能将文件内容作为:
(0, 0)
(2, 2)
(1, 1)
(3, 3)
(4, 4)

订购顺序无关紧要,但坐标x、y应该按顺序排列,即程序不应生成类似于(2,3)的内容。这种行为是否始终得到保证?我正在Linux上使用gcc编译器。


我不确定这是否有保证,但如果你想要确保的话,你可以直接发出 write() 系统调用,这在 Posix 上是保证原子性的。 - Kerrek SB
2
可能是 https://dev59.com/03RB5IYBdhLWcg3w6bYE 的重复问题。 - Tudor
1
@quartz:好吧,你要求的是保证,而不是经验测量。 - Kerrek SB
1
@KerrekSB:那是非常糟糕的建议。除非在非常特定的情况下,单个“write”不能保证是原子性的,并且“write”始终可以返回短写入,此时您将不得不再次调用“write”来写出其余部分,并且另一个线程可以在两个“write”调用之间进行竞争。另一方面,stdio对于通过相同的“FILE”流进行的其他访问是必须具有原子性的(但与通过不同的“FILE”流访问它的相同底层文件的其他用户无关)。 - R.. GitHub STOP HELPING ICE
@R..:不过实际的系统调用呢,不只是C包装函数吗?那不是原子操作吗? - Kerrek SB
显示剩余7条评论
1个回答

3
您的问题存在不兼容的假设。OpenMp不是C标准的一部分,因此C规范无法对OpenMp的线程模型做出任何说明,并确保其适当功能的安全性。直到最近,C甚至没有一个线程模型。
现在,C11有了自己的线程模型,在该线程模型中,操作IO流的函数是线程安全的:每个流都有一个相关联的锁,用于防止数据竞争,当多个执行线程访问流并限制多个线程执行的流操作交错时使用。一次只能有一个线程持有此锁。该锁是可重入的:单个线程可以同时多次持有锁。
我认为目前还没有实现完全符合C11的编译器,但通常POSIX系统上的C库将满足这个特定要求。当出现这样的符合要求的实现时,OpenMp实现将位于其上方,并记录其线程模型是否与C11的模型一致。

不只是“通常”。POSIX要求所有对stdio FILE的操作在线程方面表现出原子性。如果您想将多个独立的stdio调用分组为一个原子操作,可以使用flockfilefunlockfile函数(POSIX)。 - R.. GitHub STOP HELPING ICE
@R.. 确定。我指的是“通常情况下”,这是满足此要求的系统家族的一个示例。我不知道其他系统是否也会这样做,也不知道 POSIX 的中世纪实现(例如 OS X)是否已经具备了这一点。我记得在编写 IRIX(据说是 POSIX)时,存在许多来自不同线程的交织 IO 问题。 - Jens Gustedt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接