当同一个套接字上的send / recv正在进行时,是否可以从另一个线程关闭套接字?

时间:2010-08-28 06:24:38

标签: c sockets solaris

当同一个套接字上的send / recv正在进行时,是否可以从另一个线程关闭套接字?

假设一个线程正在阻塞recv调用而另一个线程关闭同一个套接字,那么recv调用中的线程是否会知道这个并安全地出来?

我想知道不同操作系统/平台之间的行为是否会有所不同。如果是,那么它在Solaris中的表现如何?

5 个答案:

答案 0 :(得分:4)

在Linux关闭时,套接字不会唤醒recv()。另外,正如@jxh所说:

  

如果在关闭套接字时在recv()或send()上阻塞了某个线程   通过不同的线程,被阻止的线程将收到错误。   但是,之后难以检测到正确的补救措施   收到错误。这是因为文件描述符号   与套接字相关联的可能已被不同的接收   线程,被阻止的线程现在已经被错误唤醒了   “有效”套接字。在这种情况下,唤醒线程不应该调用   close()本身。

     

醒来的线程需要一些方法来区分是否   错误是由连接(例如网络错误)产生的   要求它调用close(),或者如果错误是由a生成的   在它上面调用了close()的不同线程,在这种情况下它应该   只是在没有对套接字做任何事情的情况下出错。

因此,避免这两个问题的最佳方法是拨打shutdown()而不是close()shutdown()将使文件描述符仍然可用,因此不会被另一个描述符分配,也会因错误唤醒recv()并且recv()调用的线程可以关闭套接字正常的方式,就像发生了正常的错误一样。

答案 1 :(得分:3)

我不知道Solaris网络堆栈的实现,但我会抛弃我的理论/解释为什么它应该是安全的。

  • 线程A为此给定套接字输入一些阻塞系统调用,例如read(2)。套接字接收缓冲区中没有数据,因此线程A从处理器中取出,放入此套接字的等待队列。此处未启动网络堆栈事件,连接状态(假设TCP)未更改。
  • 线程B在套接字上发出close(2)。虽然内核套接字结构应该在线程B访问它时被锁定,但没有其他线程持有该锁(线程A在进入休眠等待时释放了锁)。假设套接字发送缓冲区中没有未完成的数据,则发送FIN数据包并且连接进入FIN WAIT 1状态(我再次假设TCP,请参阅connection state diagram
  • 我猜套接字连接状态更改会为在给定套接字上阻塞的所有线程生成唤醒。那就是线程A将进入可运行状态并发现连接正在关闭。如果对方没有发送自己的FIN,则可能会重新进入等待,否则系统调用将以eof返回。

在任何情况下,都将保护内部内核结构免受不适当的并发访问。这并不意味着从多个线程执行套接字I / O是个好主意。我建议调查非阻塞套接字,状态机和libevent等框架。

答案 2 :(得分:2)

对我来说,来自另一个线程的shutdown()套接字在Linux中执行该作业

答案 3 :(得分:1)

如果某个线程在recv()send()上被另一个线程关闭时阻塞,则阻塞的线程将收到错误。但是,在收到错误后很难检测到正确的补救措施。这是因为与套接字关联的文件描述符编号可能已被另一个线程拾取,并且阻塞的线程现在已因“有效”套接字的错误而被唤醒。在这种情况下,被唤醒的主题应调用close()本身。

唤醒线程需要一些方法来区分错误是由连接生成的(例如网络错误),要求它调用close(),还是错误是由调用的其他线程生成的close()就可以了,在这种情况下,如果没有对套接字做任何进一步的操作,它应该会出错。

答案 4 :(得分:0)

是的,可以从另一个线程关闭套接字。使用该套接字的任何阻塞/忙碌线程都将报告合适的错误。