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

Multithreading 安全地关闭无限期运行的线程,multithreading,sockets,recv,Multithreading,Sockets,Recv,首先,我意识到如果我的代码在一个循环中,当我想要线程关闭时,我可以使用do while循环来检查变量集,但是在这种情况下这是不可能的,所以看起来: DWORD WINAPI recv thread (LPVOID random) { recv(ClientSocket, recvbuffer, recvbuflen, 0); return 1; } 在上面的例子中,recv是一个阻塞函数。 如果格式不正确,请原谅。这是我在手机上能做的最好的了 既然这个线程从不关闭但从不循环,我

首先,我意识到如果我的代码在一个循环中,当我想要线程关闭时,我可以使用do while循环来检查变量集,但是在这种情况下这是不可能的,所以看起来:

DWORD WINAPI recv thread (LPVOID random) {
    recv(ClientSocket, recvbuffer, recvbuflen, 0);
    return 1;
}
在上面的例子中,recv是一个阻塞函数。 如果格式不正确,请原谅。这是我在手机上能做的最好的了

既然这个线程从不关闭但从不循环,我该如何终止它呢

谢谢,
~P

您可以在recv之前使用轮询来检查是否有东西需要接收

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 ...
} 

在其他解决方案中,您可以

a通过检查相应循环中的返回值和/或错误,为套接字设置超时并正确处理超时:

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

b用recv关闭插座。。从阻塞状态返回时出错。

我处理此问题的方法是永远不要在recv内部阻塞-最好将套接字设置为非阻塞模式,但如果知道套接字当前有一些字节可读取,也可以只调用recv

这就引出了下一个问题:如果不在recv内部阻塞,如何防止CPU旋转?这个问题的答案是使用正确的参数调用select或poll,这样您就可以在那里阻塞,直到套接字准备好接收字节为止

然后是第三个问题:如果你的线程现在可能永远在select中被阻塞,我们不是又回到了原来的问题了吗?不完全是这样,因为现在我们可以实现。特别是,因为select或poll可以同时“监视”多个套接字,所以我们可以告诉调用block,直到两个套接字中的任何一个都准备好读取数据。然后,当我们想要关闭线程时,主线程所要做的就是向第二个套接字发送一个字节的数据,这将导致select立即返回。当线程看到第二个套接字已准备好读取时,它应该通过退出来响应,以便主线程对WaitForSingleObjects的阻塞调用ThreadHandle将返回,然后主线程可以在不存在争用条件风险的情况下进行清理


最后一个问题是:如何设置套接字对,以便您的主线程可以在套接字对的其中一个套接字上调用send,并且您的recv线程将看到发送的数据显示在另一个套接字上?在POSIX下,这很简单,有一个socketpair函数正好可以做到这一点。在Windows下,socketpair不存在,但您可以滚动自己的实现,如图所示。

可能重复的呜呜声。相信我,我试着寻找答案……但这篇文章似乎对我没有多大用处。我的编译器似乎不喜欢这段代码。调用一个类类型的对象而没有合适的操作符我还没有足够的能力去寻找答案。具体来说,这个错误来自代码第六行的poll。这里给出的想法看起来很有希望。我会尽快试用的在Windows上,您不需要第二个插座。那只会不必要地浪费一个港口。改为使用WSACreateEvent创建两个事件对象,使用WSAEventSelect将其中一个与实际套接字相关联,然后使用WSAWaitForMultipleEvents等待这两个事件。当需要终止时,使用WSASetEvent发出第二个事件的信号。WSAWaitForMultipleEvents将告诉您发出信号的事件。如果使用第二个套接字,则不必向其发送数据。您可以使用shutdown关闭套接字的一侧,这将使另一侧进入ready-for-read状态。