2011-08-19 14 views

回答

4

这真的取决于你在哪个系统下运行。例如,如果您在符合POSIX的系统下运行并且线程可以取消,那么当您取消线程时,recv()调用将被中断,因为它是一个取消点。

如果你使用的是老式插座实现,你可以设置你的线程像SIGUSR1并希望大家都不信号处理其他任何人想它和信号,因为的recv()将中断的信号。如果可能的话,你最好的选择是不要阻塞。

+0

取消似乎是一个有前途的想法。线程的取消点是否有任何文档可用?我看到[链接](http://www.mkssoftware.com/docs/man3/pthread_cancel.3.asp)它没有列出任何套接字相关的调用。或者'recv()'反过来使用'read()'等其他调用,例如 – jogabonito

+0

@jogabonito如果你的系统符合posix并且使用符合posix的套接字,它将会是。 [posix取消点数](http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_05_02) –

3

我不认为关闭参与阻塞操作插座是终止操作的安全保障方式。例如,kernel.org警告黑暗:

这可能是不明智的关闭文件描述符,而他们可能会在 通过使用在同一过程中的其他线程的系统调用。由于 文件描述符可能会被重复使用,有一些模糊的竞争条件 可能会导致意想不到的副作用。

  • 相反,你可以使用一个信号,使recv失败,EINTR (确保未启用SA_RESTART)。您可以将信号发送到 特定线程与pthread_kill

  • 您可以启用插槽上SO_RCVTIMEO开始的recv 调用之前

个人而言,我通常会尽量避开所有的信号污秽的,但是这是一个可行的选择。

+0

+1为kernel.org警告.. – jogabonito

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,这会打断你的阻塞操作,给你重复操作或退出的机会。

2

,而另一个线程是不能解除分配共享资源,也可能使用它。在实践中,你会发现你甚至无法编写代码来执行你的建议。

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

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

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

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

1

如果POSIX complient系统,你可以尝试监视你的线程: 在pthread_create与功能,使你的的recvpthread_cond_signal会刚过,然后返回。
调用线程使pthread_cond_timedwait具有所需的超时值,并在timed_out时终止被调用的线程。