繁体   English   中英

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

[英]Trying to exit from a blocking UDP socket read

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

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

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

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

关闭文件描述符可能是不明智的,因为它们可能在同一进程中的其他线程中被系统调用使用。 由于文件描述符可能被重用,因此存在一些可能导致意外副作用的模糊竞争条件。

  • 相反,您可以使用信号并使用EINTR使recv失败(确保未启用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套接字读取的原因。 还有几个丑陋的黑客可用。 基本方法是使套接字无阻塞,而不是阻塞UDP套接字读取,伪造带有selectpoll的阻塞读取。 然后,您可以通过以下几种方式中止此循环:

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM