这是一个类似于 Proper way to close a blocking UDP socket的问题。我有一个在C语言中读取UDP套接字的线程,读取是阻塞的。我想知道是否可能在不依赖于recv()返回的情况下退出线程?例如,我可以从另一个线程关闭套接字并安全地期望套接字读取线程退出吗?在那个线程中没有看到任何高票答案,这就是为什么我再次提问的原因。
您可以使用信号,并使recv
失败并返回EINTR
(确保未启用SA_RESTART
)。您可以使用pthread_kill
向特定线程发送信号。
在开始recv
调用之前,您可以在套接字上启用SO_RCVTIMEO
。
针对这个问题,你有几个选项。信号将中断读取操作,所以你需要确保发出信号。recv操作应该会失败,并返回错误号EINTR。
最简单的方法是设置一个定时器,在一定时间后(例如30秒)中断进程:
itimerval timer
timeval time;
time.tv_sec = 30;
time.tv_usec = 0;
timer.it_value = time;
if( setitimer( ITIMER_REAL, &timer, NULL ) != 0 )
printf( "failed to start timer\n" );
在指定的时间之后,您将收到一个SIGALRM信号,这将中断您的阻塞操作,并为您提供重复操作或退出的机会。
当另一个线程正在使用或可能使用共享资源时,您无法释放该资源。实际上,你会发现你甚至无法编写代码来做你所建议的事情。
想一想。当你调用 close
时,你怎么可能知道另一个线程实际上被阻塞在 recv
中?如果它即将调用 recv
,但是另一个线程调用了 socket
并获取了你刚刚关闭的描述符,那么不仅该线程不会检测到任何错误,而且它将在 错误的 套接字上调用 recv
!
解决你需要退出阻塞 UDP 套接字读取的外部问题可能有一种好方法。还有几种丑陋的 hack 方法可用。基本方法是使套接字非阻塞,而不是进行阻塞 UDP 套接字读取,使用 select
或 poll
来模拟阻塞读取。然后可以通过以下几种方式中止此循环:
一种方法是让 select
超时并在 select
返回时检查“中止”标志。
另一种方法是在管道的读端上也进行 select
。发送一个字节到管道来中止 select
。