2013-07-23 48 views
6

我有C语言编写的一个多线程服务器,每个客户端线程看起来像这样:如何干净地中断阻塞recv呼叫的线程?

ssize_t n; 
struct request request; 

// Main loop: receive requests from the client and send responses. 
while(running && (n = recv(sockfd, &request, sizeof(request), 0)) == sizeof(request)) { 
    // Process request and send response. 
} 
if(n == -1) 
    perror("Error receiving request from client"); 
else if(n != sizeof(act)) 
    fprintf(stderr, "Error receiving request from client: Incomplete data\n"); 

// Clean-up code. 

在某些时候,客户满足一定的标准,它必须被断开。如果客户经常发送请求,这是没有问题的,因为它可以被告知响应中的断开;但是有时客户端需要很长时间才能发送请求,所以客户端线程最终会阻塞recv调用,并且客户端在下一个请求/响应之前不会断开连接。

有一个干净的方式,而在客户端线程在recv呼叫阻塞从另一个线程断开客户端?我尝试了close(sockfd),但这会导致发生错误Error receiving request from client: Bad file descriptor,这确实不准确。

另外,有我在这里处理错误更好的办法?

+2

可能的重复http://stackoverflow.com/questions/6910335/interrupting-syscalls-in-threads-on-linux –

+0

@DrewMcGowen谢谢,我看了类似的线程,但我设法错过了那一个。尽管如此,仍然不确定这是一个完全相同的问题,因为彻底杀死这个线程并不是我真正想要的。 – DanielGibbs

+0

它何况,它使用任何安装的信号处理程序,所以你也许可以用它来清理 –

回答

6

所以,你至少有这种可能性:

(1)pthread_kill会吹线程出recv,并且errno == EINTR,你可以清理并退出你自己的线程。有些人认为这很讨厌。取决于,真的。 (2)使您的客户端套接字非阻塞,并使用select在输入中等待特定时间段,然后检查线程之间使用的开关是否已设置为指示它们应该关闭。

(3)在与(2)具有每个线程共享与主螺纹的管的组合。将它添加到select。如果它变得可读并且包含一个shutdonw请求,则该线程会自行关闭。

(4)寻找到pthread_cancel机制,如果没有以上(或其变体)不符合您的需求。

+0

对,如果我用'SIGUSR1'调用'pthread_kill',然后检查'errno'是否为'EINTR',那么这应该工作?我需要为'SIGUSR'的线程添加一个信号处理程序吗?如果是这样,它应该怎么做? – DanielGibbs

+1

信号处理程序设置一个开关。当你得到EINTR时,你检查开关,如果它打开,那么你清理并出去。我回答了一个有点类似于这个问题,或多或少涵盖了基本知识http://stackoverflow.com/a/17607149/63743 – Duck

+0

'pthread_kill'只会导致'EINTR'如果你安装信号处理程序没有' SA_RESTART'选项。这种方法也有导致信号丢失的竞争条件,但您可能并不关心这一点,从某种意义上说,您不得不修改程序的全局状态(信号处置)以使用它,这不是“库安全”的。 'pthread_cancel'确实是正确的解决方案。 –

3

关闭从另一个线程输入插座。这将导致阅读线程收到一个EOS,这会导致它关闭套接字并在正确写入时终止。

+0

注意:我认为@EJP说'shutdown'时,他意味着对'shutdown'的文字调用,即对'close'的调用不会中断该线程。 – chacham15

+0

@checham'关闭输入的套接字'只有一个含义。我没有在任何地方使用'close'这个词。你真的没有帮助。 – EJP

+0

认为close会导致关机是一个自然的假设。因此,我写了我的评论来澄清其他可能误解我的人。没有必要是敌对的。 – chacham15