简体   繁体   English

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

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

This is a question similar to Proper way to close a blocking UDP socket . 这是一个类似于关闭阻塞UDP套接字的正确方法的问题。 I have a thread in C which is reading from a UDP socket. 我在C中有一个线程,它从UDP套接字读取。 The read is blocking. 读取是阻止的。 I would like to know if it is possible to be able to exit the thread, without relying on the recv() returning? 我想知道是否有可能退出线程,而不依赖于recv()返回? For example can I close the socket from another thread and safely expect the socket read thread to exit? 例如,我可以从另一个线程关闭套接字并安全地期望套接字读取线程退出吗? Didn't see any high voted answer on that thread, thats why I am asking it again. 在那个帖子上没有看到任何高投票的答案,这就是为什么我再次问它。

This really depends on what system you're running under. 这实际上取决于您正在运行的系统。 For example, if you're running under a POSIX-compliant system and your thread is cancelable, the recv() call will be interrupted when you cancel the thread since it's a cancel point. 例如,如果您在符合POSIX的系统下运行且线程可取消,则取消线程时recv()调用将被中断,因为它是取消点。

If you're using an older socket implementation, you could set a signal handler for your thread for something like SIGUSR1 and hope nobody else wanted it and signal, since recv() will interrupt on a signal. 如果您正在使用较旧的套接字实现,您可以为您的线程设置SIGUSR1之类的信号处理程序,并希望没有其他人想要它并发出信号,因为recv()将中断信号。 Your best option is not to block, if at all possible. 如果可能的话,你最好的选择是不要阻止。

I don't think closing a socket involved in a blocking operation is a safe guaranteed way of terminating the operation. 我不认为关闭阻塞操作中涉及的套接字是终止操作的安全保证方式。 For instance, kernel.org warns darkly: 例如, kernel.org黑暗警告:

It is probably unwise to close file descriptors while they may be in use by system calls in other threads in the same process. 关闭文件描述符可能是不明智的,因为它们可能在同一进程中的其他线程中被系统调用使用。 Since a file descriptor may be reused, there are some obscure race conditions that may cause unintended side effects. 由于文件描述符可能被重用,因此存在一些可能导致意外副作用的模糊竞争条件。

  • Instead you could use a signal and make recv fail with EINTR (make sure SA_RESTART is not enabled). 相反,您可以使用信号并使用EINTR使recv失败(确保未启用SA_RESTART )。 You can send a signal to a specific thread with pthread_kill 您可以使用pthread_kill向特定线程发送信号

  • You could enable SO_RCVTIMEO on the socket before starting the recv call 您可以在启动recv调用之前在套接字上启用SO_RCVTIMEO

Personally I usually try to stay clear of all the signal nastiness but it's a viable option. 就个人而言,我通常会试图避开所有信号的肮脏,但这是一个可行的选择。

You've got a couple of options for that. 你有几个选择。 A signal will interrupt the read operation, so all you need to do is make sure a signal goes off. 信号将中断读操作,因此您需要做的就是确保信号熄灭。 The recv operation should fail with error number EINTR. recv操作应该失败,错误号为EINTR。

The simplest option is to set up a timer to interrupt your own process after some timeout eg 30 seconds: 最简单的选择是设置一个计时器,在一些超时后中断你自己的进程,例如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" );

You'll get a SIGALRM after the specified time, which will interrupt your blocking operation, and give you the chance to repeat the operation or quit. 您将在指定时间后获得SIGALRM,这将中断您的阻止操作,并让您有机会重复操作或退出。

You cannot deallocate a shared resource while another thread is or might be using it. 当另一个线程正在或可能正在使用共享资源时,您无法释放共享资源。 In practice, you will find that you cannot even write code to do what you suggest. 在实践中,您会发现您甚至无法编写代码来执行您的建议。

Think about it. 想一想。 When you go to call close , how can you possibly know that the other thread is actually blocked in recv ? 当你打电话给close ,你怎么可能知道另一个线程实际上在recv被阻止了? What if it's about to call recv , but then another thread calls socket and gets the descriptor you just closed? 如果要调用recv ,然后另一个线程调用socket并获取刚刚关闭的描述符,该怎么办? Now, not only will that thread not detect any error, but it will be calling recv on the wrong socket! 现在,不仅该线程没有检测到任何错误,而且它将在错误的套接字上调用recv

There is probably a good way to solve your outer problem, the reason you need to exit from a blocking UDP socket read. 可能有一种很好的方法来解决您的外部问题,这是您需要退出阻塞UDP套接字读取的原因。 There are also several ugly hacks available. 还有几个丑陋的黑客可用。 The basic approach is to make the socket non-blocking and instead of making a blocking UDP socket read, fake a blocking read with select or poll . 基本方法是使套接字无阻塞,而不是阻塞UDP套接字读取,伪造带有selectpoll的阻塞读取。 You can then abort this loop several ways: 然后,您可以通过以下几种方式中止此循环:

One way is to have select time out and check an 'abort' flag when select returns. 一种方法是select超时并在select返回时检查'abort'标志。

Another way is to also select on the read end of a pipe. 另一种方法是在管道的读取端select Send a single byte to the pipe to abort the select . 将单个字节发送到管道以中止select

If posix complient system, you can try to monitor your thread: pthread_create with a function that makes your recv and pthread_cond_signal just after, then returns. 如果是posix complient系统,你可以尝试监视你的线程: pthread_create ,其功能使你的recvpthread_cond_signal紧随其后,然后返回。
The calling thread makes a pthread_cond_timedwait with the desired timeout and terminates the called thread if timed_out. 调用线程使用所需的超时生成pthread_cond_timedwait ,并在timed_out时终止被调用的线程。

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

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