10

如果我有一个套接字,s当前没有可用的数据,它是一个阻塞套接字,并且我recv同时从两个线程调用它,会发生什么?其中一个线程会获取数据吗?双方都会得到吗?第二次调用会recv返回错误吗?

4

4 回答 4

10

一个线程会得到它,没有办法告诉它。

这似乎不是一个合理的设计。为什么需要两个线程recv()在同一个套接字上调用是有原因的吗?

于 2009-03-18T23:42:38.600 回答
3

套接字实现应该是线程安全的,因此只有一个线程应该在数据可用时获取数据。另一个电话应该只是阻塞。

于 2009-03-18T23:23:53.153 回答
3

我找不到这方面的参考,但这是我的理解:

供应商对线程安全的保证可能仅意味着多个线程可以各自安全地使用自己套接字;它不保证单个调用的原子性,也不保证套接字数据在多个线程之间的任何特定分配。

假设线程 A 在一个套接字上调用 recv(),该套接字以高速率接收 TCP 数据流。如果 recv() 需要是原子调用,那么线程 A 可以阻止所有其他线程执行,因为它需要连续运行以提取所有数据(直到它的缓冲区已满,无论如何)。好的。因此,我不会假设 recv() 不受上下文切换的影响。

相反,假设线程 A 在 TCP 套接字上对 recv() 进行了阻塞调用,并且数据进入缓慢。因此,对 recv() 的调用返回时将 errno 设置为 EAGAIN。

在这两种情况下,假设线程 B 在同一个套接字上调用 recv(),而线程 A 仍在接收数据。线程 A 什么时候停止接收数据,以便线程 B 可以开始接收数据?我不知道 Unix 实现会尝试记住线程 A 正在套接字上的操作中间;相反,由应用程序(线程 A 和 B)来协商他们对它的使用。

通常,最好将应用程序设计为只有一个线程会在单个套接字上调用 recv()。

于 2009-03-18T23:49:33.733 回答
2

从recv的手册页

SOCK_STREAM 套接字上的 recv() 返回与提供的缓冲区大小一样多的可用信息。

假设您使用的是 TCP,因为问题中没有指定它。所以假设你有线程 A 和线程 B 都阻塞在 socket 的 recv() 上。一旦 s 有一些数据要接收,它将解除阻塞其中一个线程,比如说 A,并返回数据。就我们而言,返回的数据将是一些随机大小。线程 A 检查接收到的数据并确定它是否具有完整的“消息”,其中消息是应用程序级别的概念。

线程 A 确定它没有完整的消息,因此它再次调用 recv()。但与此同时,B 已经阻塞在同一个套接字上,并且已经收到了用于线程 A 的其余“消息”。我在这里松散地使用了预期。

现在线程 A 和线程 B 都有一个不完整的消息,并且会根据代码的编写方式将数据作为无效数据丢弃,或者导致奇怪和微妙的错误。

我希望我可以说我从经验中不知道这一点。

因此,虽然 recv() 本身在技术上是线程安全的,但如果您将它用于 TCP,那么让两个线程同时调用它是一个坏主意。

据我所知,使用 UDP 是完全安全的。

我希望这有帮助。

于 2009-03-27T21:34:03.150 回答