【发布时间】:2010-10-14 05:02:40
【问题描述】:
如果我有一个套接字,s,目前没有可用的数据,它是一个阻塞套接字,我同时从两个线程调用recv,会发生什么?其中一个线程会获取数据吗?双方都会得到吗?对recv 的第二次调用会返回错误吗?
【问题讨论】:
如果我有一个套接字,s,目前没有可用的数据,它是一个阻塞套接字,我同时从两个线程调用recv,会发生什么?其中一个线程会获取数据吗?双方都会得到吗?对recv 的第二次调用会返回错误吗?
【问题讨论】:
一个线程会得到它,没有办法告诉它。
这似乎不是一个合理的设计。为什么需要两个线程在同一个套接字上调用recv()?
【讨论】:
套接字实现应该是线程安全的,因此只有一个线程应该在数据可用时获取数据。另一个调用应该只是阻塞。
【讨论】:
我找不到这方面的参考资料,但这是我的理解:
供应商对线程安全的保证可能仅意味着多个线程可以各自安全地使用其自己的套接字;它不保证单个调用的原子性,也不保证套接字数据在多个线程之间的任何特定分配。
假设线程 A 在一个套接字上调用 recv(),该套接字以高速率接收 TCP 数据流。如果 recv() 需要是原子调用,那么线程 A 可以阻止所有其他线程执行,因为它需要连续运行以提取所有数据(直到它的缓冲区已满,无论如何)。好的。因此,我不会假设 recv() 不受上下文切换的影响。
相反,假设线程 A 在 TCP 套接字上对 recv() 进行 阻塞 调用,并且数据进入缓慢。因此,对 recv() 的调用返回时将 errno 设置为 EAGAIN。
在任何一种情况下,假设线程 B 在同一个套接字上调用 recv(),而线程 A 仍在接收数据。线程 A 什么时候停止接收数据,以便线程 B 可以开始接收数据?我不知道有一个 Unix 实现会尝试记住线程 A 正在对套接字进行操作;相反,由应用程序(线程 A 和 B)协商使用它。
通常,最好将应用程序设计为只有一个线程会在单个套接字上调用 recv()。
【讨论】:
来自recv上的man page
SOCK_STREAM 套接字上的 recv() 返回尽可能多的可用信息 因为提供的缓冲区的大小可以 持有。
假设您使用的是 TCP,因为问题中没有指定它。所以假设你有线程 A 和线程 B 都阻塞在 socket 的 recv() 上。一旦 s 有一些数据要接收,它将解除阻塞其中一个线程,比如说 A,并返回数据。就我们而言,返回的数据将是一些随机大小。线程 A 检查接收到的数据并确定它是否具有完整的“消息”,其中消息是应用程序级别的概念。
线程 A 确定它没有完整的消息,因此它再次调用 recv()。但与此同时 B 已经阻塞在同一个套接字上,并且已经收到了用于线程 A 的其余“消息”。我在这里松散地使用了。
现在线程 A 和线程 B 都有一条不完整的消息,并且会根据代码的编写方式将数据作为无效数据丢弃,或者导致奇怪和微妙的错误。
我希望我可以说我从经验中不知道这一点。
因此,虽然 recv() 本身在技术上是线程安全的,但如果您将它用于 TCP,那么让两个线程同时调用它是一个坏主意。
据我所知,使用 UDP 是完全安全的。
我希望这会有所帮助。
【讨论】: