12

如果你在两个不同的线程中调用read(或write,或两者),在同一个文件描述符上(假设我们对本地文件感兴趣,它是一个套接字文件描述符),而不显式使用同步机制,会发生什么?

Read 和 Write 是系统调用,因此,在单核 CPU 上,“同时”执行两次读取可能是不幸的。但是多核...

linux内核会做什么?

让我们更笼统一点:其他内核(如 BSD)的行为是否总是相同的?

编辑:根据关闭文档,我们应该确保文件描述符没有被其他线程中的系统调用使用。所以它接缝在关闭文件描述符之前需要显式同步(因此,如果可能调用它的线程仍在运行,也围绕读/写)。

4

4 回答 4

16

在所有主流的类 UNIX 操作系统中,任何系统级(系统调用)文件描述符访问都是线程安全的。尽管取决于年龄,但它们不一定是信号安全的。

如果您在两个不同任务的文件描述符上调用read、或类似名称write,则内核的内部锁定机制将解决争用。accept

对于读取,每个字节可能只读取一次,并且写入将以任何未定义的顺序进行。

stdio 库函数freadfwriteco。默认情况下,控制结构上也有内部锁定,尽管通过使用标志可以禁用它。

于 2013-07-02T17:32:04.873 回答
3

关于 close 的评论是因为在其他线程可能试图使用它的任何情况下关闭文件描述符都没有多大意义。因此,虽然就内核而言它是“安全的”,但它可能会导致奇怪的、难以诊断的极端情况。

如果一个线程在第二个线程尝试读取文件描述符时关闭文件描述符,则第二个线程可能会收到意外的 EBADF 错误。更糟糕的是,如果第三个线程同时打开一个新文件,这可能会重新分配相同的 fd,并且第二个线程可能会意外地从新文件中读取,而不是从它预期的文件中读取......

于 2013-07-02T20:49:23.353 回答
2

关心那些追随你脚步的人

使用互斥信号量保护文件描述符是完全正常的。它消除了对内核行为的任何依赖,因此您的消息边界现在是确定的。然后,您不必引用 15,489 行联机帮助页底部的最后一段,它解释了为什么不需要互斥锁(我夸大了,但你明白我的意思)

它还使阅读您的代码的任何人都清楚文件描述符被多个线程使用。

附加福利

以这种方式使用互斥锁有一个附带的好处。假设您收到来自不同线程的不同消息,并且其中一些消息比其他消息更重要。您需要做的就是设置线程优先级以反映其消息的重要性。这样,操作系统将确保您的消息将按重要性顺序发送,而您只需付出最少的努力。

于 2013-07-03T04:49:11.533 回答
0

结果将取决于线程如何安排在该特定时刻运行。

使用多线程可能避免未定义行为的一种方法是假设您正在执行内存操作。例如更新链表或更改变量等。

如果您使用 mutex/semaphores/lock 或其他一些同步机制,它应该可以按预期工作。

于 2013-07-02T17:34:31.893 回答