【问题标题】:Is it safe to issue blocking write() calls on the same TCP socket from multiple threads?从多个线程在同一个 TCP 套接字上发出阻塞 write() 调用是否安全?
【发布时间】:2010-11-30 05:53:33
【问题描述】:

假设我有两个线程,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 - 我知道这样做不是一个好主意。我正在尝试确定某些我没有编写的代码是否正确。

【问题讨论】:

  • 我们在谈论什么操作系统?
  • Linux。 (如果其他版本的 Unix 的答案不同,我会很感兴趣,例如 OpenBSD 或 OS X)。
  • 我不知道 'Nix 系统,但是在 Windows 上,TCP 将两个写操作交织在一起,需要在代码中加锁以防止同时多线程访问套接字以防止重叠。
  • 我想你已经回答了你自己的问题。无论目标平台是否存在系统调用原子性错误,这都是一种糟糕的做法。

标签: linux sockets multithreading tcp


【解决方案1】:

它尝试

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


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

Linux 以“通常”为人所知1. 正确,但它有一个错误,即使在最近的内核中也是如此。它确实会尝试锁定套接字,但在某些情况下,内存分配可能会失败并且写入会被拆分。有关详细信息,请参阅this IBM blog entry on sendmsg。 [链接已修复]

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


1。 TL;DR:几乎总是,即,除非出现特定错误,否则总是。

【讨论】:

  • 您链接到的页面末尾的表格显示 FreeBSD 和 OS X 也不提供原子套接字发送(所以我们可以安全地假设您感到震惊吗?;)。不过我不确定这是一个错误 - 我相信这是该页面中的重点语句:作为一个大问题,POSIX/SUSv3 标准开发人员表示套接字 I/O 的原子性是“未指定的”。
  • Si,我猜对大多数人来说,多线程写入并不是一个现实的测试用例。好点。
  • 那个链接失效了,好像在quark.tistory.com/m/post/235有一个副本
  • 谢谢,链接已重新指向 Internet 档案馆的 WayBack 机器。
  • @gavv -- 数据报不同,每次写入都会创建一个新的,所以我敢打赌这个问题不适用。至于标准,没关系,无论规范是否如此,写入都被合理地预期是原子的。
猜你喜欢
  • 2010-10-14
  • 2017-07-15
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 2014-06-20
相关资源
最近更新 更多