2010-08-28 19 views
11

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

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

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

回答

2

我不知道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

0

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

+6

在linux atleast似乎并没有像那样报道。即使我们从另一个线程调用close,阻塞的recv线程仍然被阻塞。 – Jay 2010-09-02 10:42:02

2

对于我来说,关机()从另一个线程插槽做的工作在Linux中

+2

欢迎来到stackoverflow.com。你可以通过提供一些对断言或提供一个简短例子的文档的引用来改进你的答案。 “适合你”的答案没有帮助,因为它可能不适用于其他人。 – stefan 2013-05-24 09:39:21

1

如果一个线程被阻塞recv()send()当插座是由不同的线程关闭,被阻塞的线程将收到一个错误。但是,收到错误后很难检测到正确的补救措施。这是因为与套接字关联的文件描述符编号可能已经被另一个线程拾取,并且被阻塞的线程现在被错误唤醒以用于“有效”套接字。在这种情况下,醒来的线程应该是而不是请致电close()本身。

被唤醒的线程将需要一些方法来区分错误是否是由连接(例如网络错误)产生的,需要它调用close(),或者错误是由其他线程在其上调用close()生成的,在这种情况下,它应该只是在没有对套接字进行任何操作的情况下出错。

3

在linux关闭套接字时不会唤醒recv()。此外,作为@jxh说:

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

的唤醒线程都需要一些方法来区分是否被连接(例如网络故障),其 需要它来调用close()产生的 错误,或者产生差错由 不同的线程在它上面调用close(),在这种情况下,它应该只是出错,而不会对套接字做任何进一步处理。

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

相关问题