尝试退出阻塞的UDP套接字读取

时间:2011-08-19 06:52:12

标签: c sockets

这是一个类似于Proper way to close a blocking UDP socket的问题。我在C中有一个线程,它从UDP套接字读取。读取是阻止的。我想知道是否有可能退出线程,而不依赖于recv()返回?例如,我可以从另一个线程关闭套接字并安全地期望套接字读取线程退出吗?在那个帖子上没有看到任何高投票的答案,这就是为什么我再次问它。

5 个答案:

答案 0 :(得分:4)

这实际上取决于您正在运行的系统。例如,如果您在符合POSIX的系统下运行且线程可取消,则取消线程时recv()调用将被中断,因为它是取消点。

如果你正在使用旧的套接字实现,你可以为你的线程设置SIGUSR1之类的信号处理程序,并希望没有其他人想要它并发出信号,因为recv()会中断信号。如果可能的话,你最好的选择不是阻止。

答案 1 :(得分:3)

我不认为关闭阻塞操作中涉及的套接字是终止操作的安全保证方式。例如,kernel.org黑暗警告:

  

关闭文件描述符可能是不明智的   在同一进程中的其他线程中使用系统调用。既然一个   文件描述符可以重用,有一些模糊的竞争条件   这可能会导致意想不到的副作用。

  • 相反,您可以使用信号并使recv失败并显示EINTR (确保未启用SA_RESTART)。你可以发信号到 具有pthread_kill

  • 的特定主题
  • 您可以在启动recv之前在套接字上启用SO_RCVTIMEO 调用

就我个人而言,我通常会尽量避免所有的信号肮脏,但这是一个可行的选择。

答案 2 :(得分:2)

你有几个选择。信号将中断读操作,因此您需要做的就是确保信号熄灭。 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,这将中断您的阻止操作,并让您有机会重复操作或退出。

答案 3 :(得分:2)

当另一个线程正在或可能正在使用它时,您无法释放共享资源。在实践中,你会发现你甚至不能编写代码来做你的建议。

想一想。当你打电话给close时,你怎么可能知道recv实际阻止了另一个线程?如果要调用recv,然后另一个线程调用socket并获取刚关闭的描述符,该怎么办?现在,该线程不仅不会检测到任何错误,而且会在错误的套接字上调用recv

可能有一种很好的方法可以解决您的外部问题,这是您需要退出阻塞UDP套接字读取的原因。还有几个丑陋的黑客可用。基本方法是使套接字无阻塞,而不是阻塞UDP套接字读取,伪造阻塞读取selectpoll。然后,您可以通过以下几种方式中止此循环:

一种方法是select超时,并在select返回时检查'中止'标志。

另一种方法是在管道的读取端也select。将单个字节发送到管道以中止select

答案 4 :(得分:1)

如果是posix complient系统,你可以尝试监控你的线程: pthread_create ,其功能使您的 recv pthread_cond_signal 紧随其后,然后返回。
调用线程使用所需的超时生成 pthread_cond_timedwait ,并在timed_out时终止被调用的线程。