当套接字关闭时取消阻止recvfrom
假设我启动一个线程在端口上接收。套接字调用将在recvfrom 上阻塞。 然后,以某种方式在另一个线程中,我关闭了套接字。
在Windows 上,这将解除recvfrom 的阻塞,并且我的线程执行将终止。
在 Linux 上,这不会阻止接收,因此,我的线程永远什么都不做,并且线程执行不会终止。
谁能帮我解决 Linux 上发生的事情吗?当套接字关闭时,我希望 recvfrom 解除阻止
我继续阅读有关使用 select() 的信息,但我不知道如何在我的具体情况下使用它。
Let's say I start a thread to receive on a port. The socket call will block on recvfrom.
Then, somehow in another thread, I close the socket.
On Windows, this will unblock recvfrom and my thread execution will terminate.
On Linux, this does not unblock recvfrom, and as a result, my thread is sitting doing nothing forever, and the thread execution does not terminate.
Can anyone help me with what's happening on Linux? When the socket is closed, I want recvfrom to unblock
I keep reading about using select(), but I don't know how to use it for my specific case.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在套接字上调用 shutdown(sock, SHUT_RDWR),然后等待线程退出。 (即
pthread_join
)。您可能会认为
close()
会解锁recvfrom()
,但在 Linux 上却不然。Call
shutdown(sock, SHUT_RDWR)
on the socket, then wait for the thread to exit. (i.e.pthread_join
).You would think that
close()
would unblock therecvfrom()
, but it doesn't on linux.下面是使用 select() 处理此问题的简单方法的草图:
更优雅的方法是避免使用 select 的超时功能,而是创建一个套接字对(使用 socketpair())并让主线程当它希望 I/O 线程离开时,在套接字对的一端发送一个字节;当 I/O 线程在套接字对另一端的套接字上接收到一个字节时,让 I/O 线程退出。不过,我会将其作为练习留给读者。 :)
将套接字设置为非阻塞模式通常也是一个好主意,以避免即使在 select() 指示套接字已准备好之后,recvfrom() 调用也可能阻塞的(小但非零)机会-read,如此处所述。但阻塞模式对于您的目的来说可能“足够好”。
Here's a sketch of a simple way to use select() to deal with this problem:
A more elegant method would be to avoid using the timeout feature of select, and instead create a socket pair (using socketpair()) and have the main thread send a byte on its end of the socket pair when it wants the I/O thread to go away, and have the I/O thread exit when it receives a byte on its socket at the other end of the socketpair. I'll leave that as an exercise for the reader though. :)
It's also often a good idea to set the socket to non-blocking mode also, to avoid the (small but non-zero) chance that the recvfrom() call might block even after select() indicated the socket is ready-to-read, as described here. But blocking mode might be "good enough" for your purpose.
不是答案,但 Linux close 手册页包含有趣的引用:
Not an answer, but the Linux close man page contains the interesting quote:
你正在要求不可能的事情。调用
close
的线程根本不可能知道另一个线程在recvfrom
中被阻塞。尝试编写保证这种情况发生的代码,你会发现这是不可能的。无论您做什么,对
close
的调用始终有可能与对recvfrom
的调用竞争。对close
的调用改变了套接字描述符所指的内容,因此它可以改变对recvfrom
的调用的语义。进入recvfrom的线程无法以某种方式向调用close的线程发出信号,表明它已被阻塞(而不是即将阻塞或刚刚进入系统)称呼)。因此,实际上没有可能的方法来确保
close
和recvfrom
的行为是可预测的。请考虑以下情况:
recvfrom
,但它被系统需要执行的其他操作抢占。close
。socket
并获取与您关闭
相同的描述符。recvfrom
,现在它正在从库打开的套接字接收数据。哎呀。
永远不要做这样的事,哪怕是远程的事。当另一个线程正在或可能正在使用资源时,不得释放该资源。时期。
You are asking for the impossible. There is simply no possible way for the thread that calls
close
to know that the other thread is blocked inrecvfrom
. Try to write code that guarantees that this happens, you will find that it is impossible.No matter what you do, it will always be possible for the call to
close
to race with the call torecvfrom
. The call toclose
changes what the socket descriptor refers to, so it can change the semantic meaning of the call torecvfrom
.There is no way for the thread that enters
recvfrom
to somehow signal to the thread that callsclose
that it is blocked (as opposed to being about to block or just entering the system call). So there is literally no possible way to ensure the behavior ofclose
andrecvfrom
are predictable.Consider the following:
recvfrom
, but it gets pre-empted by other things the system needs to do.close
.socket
and gets the same decsriptor as the one youclose
d.recvfrom
, and now it's receiving from the socket the library opened.Oops.
Don'd ever do anything even remotely like this. A resource must not be released while another thread is, or might be, using it. Period.