问题:从多个线程在同一个 TCP 套接字上发出阻塞 write() 调用是否安全?

假设我有两个线程,T1 和 T2。

线程 T1 在 TCP 套接字 S 上进行阻塞式 write() 调用,以发送字节 B1 的大缓冲区。字节 B1 的缓冲区非常大,以至于 (a) 写调用阻塞和 (b) TCP 必须使用多个段来发送缓冲区。

线程 T2 还在同一个 TCP 套接字 S 上进行阻塞 write() 调用,以发送一些其他大的字节 B2 缓冲区。

我的问题是这样的:

UNIX 上的 TCP 实现是否保证 B1 的所有字节将在 B2 的所有字节之前发送(反之亦然)?

或者 TCP 是否有可能交错 B1 和 B2 的内容(例如 TCP 发送一个带有 B1 数据的段,然后是一个带有 B2 数据的段,然后又是一个带有 B1 数据的段)。

PS - 我知道这样做不是一个好主意。我正在尝试确定我没有编写的某些代码是否正确。

解答

它尝试

TL;DR: 出于编写和调试代码的目的,假设原子性是安全的,除非您的目标是生命支持系统。


如果 tcp 套接字上的send(2)(与write(2)相同)不是原子的,那总是会很糟糕。实现非原子写入永远没有充分的理由。 Unix 和 Windows 的所有版本都试图保持写入的原子性,但显然很少有提供保证。

Linux以_“通常”_1而闻名。做对了,但它有一个错误,即使在最近的内核中也是如此。它确实会尝试锁定套接字,但在某些情况下,内存分配可能会失败并且写入会被拆分。有关详细信息,请参阅 sendmsg](https://web.archive.org/web/20120914000315/http://www.almaden.ibm.com/cs/people/marksmith/sendmsg.html)上的[这个 IBM 博客条目。 [链接已修复。]

根据这些测试,只有 AIX 和 Solaris 完全通过了线程压力测试。甚至那些系统是否也有根本没有被发现的故障案例是未知的。


1\。 TL;DR:几乎总是,即,总是除非出现某种错误。

Logo

更多推荐