从两个线程调用相同的阻塞套接字上的recv()

时间:2009-03-18 22:58:16

标签: c sockets system recv

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

4 个答案:

答案 0 :(得分:10)

一个线程会得到它,并且没有办法分辨哪个。

这似乎不是一个合理的设计。您是否有理由在同一个套接字上需要两个线程调用recv()

答案 1 :(得分:3)

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

答案 2 :(得分:3)

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

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

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

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

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

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

答案 3 :(得分:2)

来自recv上的man page

  

SOCK_STREAM套接字上的recv()   返回尽可能多的可用信息   因为提供的缓冲区的大小可以   持。

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

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

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

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

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

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

我希望这会有所帮助。