安全地关闭无限期运行的线程

时间:2014-11-11 14:49:07

标签: multithreading sockets recv

首先,我意识到如果我的代码在循环中,我可以使用do while循环来检查变量集,当我希望线程关闭时,但在这种情况下这是不可能的(所以似乎):

DWORD WINAPI recv thread (LPVOID random) {
    recv(ClientSocket, recvbuffer, recvbuflen, 0);
    return 1;
}

在上面,recv()是一个阻塞函数。 (如果格式不正确,请原谅我。这是我在手机上做的最好的。)

我将如何终止此线程,因为它永远不会关闭但永远不会循环?

谢谢, 〜P

3 个答案:

答案 0 :(得分:1)

除了其他解决方案之外,您还可以

a)通过在适当的循环中检查返回值和/或错误来正确设置套接字超时和处理超时:

setsockopt(ClientSocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout))

b)关闭套接字recv(..)从阻塞状态返回错误。

答案 1 :(得分:0)

您可以在recv()之前使用poll来检查是否有某些内容可以接收。

struct pollfd poll;
int res;

poll.fd = ClientSocket;
poll.events = POLLIN;
res = poll(&poll, 1, 1000); // 1000 ms timeout

if (res == 0)
{
    // timeout
}
else if (res == -1)
{
    // error
}
else
{
    // implies (poll.revents & POLLIN) != 0
    recv(ClientSocket, recvbuffer, recvbuflen,0); // we can read ...
} 

答案 2 :(得分:0)

我处理这个问题的方法是永远不要阻塞recv() - 最好是通过将套接字设置为非阻塞模式,但是当你知道它时,你也可以简单地只调用recv()。 socket目前有一些字节可供读取。

这导致了下一个问题:如果你不阻止内部recv(),你如何防止CPU旋转?这个问题的答案是用正确的参数调用select()(或poll()),这样你就可以阻塞,直到套接字的字节准备好recv()。

然后是第三个问题:如果您的线程现在在select()中被阻止(可能永远),那么我们是否还会再次回到原来的问题?不完全是因为现在我们可以实现self-pipe trick的变体。特别是因为select()(或poll())可以观看'同时多个套接字,我们可以告诉阻塞调用,直到两个套接字中的任何一个都有数据准备读取。然后,当我们想要关闭线程时,所有主线程要做的就是将单个字节的数据发送到第二个套接字,这将导致select()立即返回。当线程看到它是第二个已准备好读取的套接字时,它应该通过退出来响应,这样主线程对WaitForSingleObject(theThreadHandle)的阻塞调用将返回,然后主线程可以清理没有任何竞争条件的风险。

最后一个问题是:如何设置套接字对,以便主线程可以在其中一个套接字上调用send(),并且你的recv-thread将看到发送的数据出现在其他插座?在POSIX下它很容易,有一个socketpair()函数就是这么做的。在Windows下,socketpair()不存在,但您可以按照here所示滚动自己的实现。