繁体   English   中英

如何干净地中断recv调用中的线程阻塞?

[英]How to cleanly interrupt a thread blocking on a recv call?

我有一个用C编写的多线程服务器,每个客户端线程看起来像这样:

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发生Error receiving request from client: Bad file descriptor ,这实际上是不正确的。

或者,有没有更好的方法让我在这里处理错误?

因此,您至少具有以下可能性:

(1) pthread_kill将使用errno == EINTR将线程从recv吹出,您可以自行清理并退出线程。 有人认为这很讨厌。 取决于,真的。

(2)使您的客户端套接字不阻塞,并使用select等待输入特定的时间,然后检查线程之间使用的开关是否已设置为指示它们应该关闭。

(3)与(2)组合,使每个线程与主线程共享一个管道。 将其添加到select 如果它变得可读并包含关闭请求,则线程将自行关闭。

(4)如果以上(或其变体)都不满足您的需求,请查看pthread_cancel机制。

关闭套接字以从另一个线程输入。 这将导致读取线程收到一个EOS,这将导致它关闭套接字并在正确写入后终止。

要中断线程,请使套接字成为非阻塞套接字(使用fcntl设置O_NONBLOCK ),然后向线程发出pthread_kill信号。 这样, recv将在EINTR处于睡眠状态时失败,或者如果EAGAINEWOULDBLOCK睡眠状态,则失败(也可能是SA_RESTART生效,没有检查)。 请注意,在此之前,套接字不需要并且实际上应该是非阻塞的。 (当然需要处理信号;空的处理程序就足够了)。

为确保捕捉到停止信号,但别无其他,请使用标志; 有些事情可能出问题了。 例如, recv可能在某些杂散信号上对EINTR失败。 或者,如果有一些可用数据,它可能会成功,实际上忽略了停止请求。

以及不该做的事:

  1. 不要单独使用pthread_kill或进行简单检查。 它可能在发出recv syscall之前就到达,为时过早,无法中断,但要经过所有检查。

  2. 不要close插座。 这可能甚至行不通,而且@R ..指针向外输出很危险,因为套接字文件描述符可能在closerecv之间重用(除非您确定没有打开文件描述符)。

暂无
暂无

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

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