我有一个用C ++编写的Windows服务,它充当TCP服务器,用于侦听传入连接。
我初始化了服务器套接字并将accept
代码放在一个单独的线程中。这将接受并处理传入的连接。
但是,我还需要在服务收到STOP信号时停止此线程。所以我想到了使用CreateEvent
创建一个事件对象并等待它发出信号。这种等待将在创建接受线程的线程中发生。所以我可以使用TerminateThread
函数在收到STOP信号时停止接受线程。
然而,MSDN表示
TerminateThread是一个危险的函数,只能在最极端的情况下使用。
应该严格遵循这一点,我的方法是否正确?这可能是另一种方式吗?
答案 0 :(得分:2)
在Windows中,只需拨打accept
即可从其他线程唤醒阻止closesocket
来电。阻塞accept
调用将返回-1,并且您的代码有机会通过检查已设置的其他退出条件(例如全局变量)来突破其所处的循环
这也适用于具有close
功能的Mac(以及可能的BSD衍生产品),但不适用于Linux。针对此问题的更通用的UNIX解决方案是here。
以下Windows解决方案的一些pseduo代码。
SOCKET _listenSocket;
bool _needToExit = false;
HANDLE _hThread;
void MakeListenThreadExit()
{
_needToExit = true;
closesocket(_listenSocket);
_listenSocket = INVALID_SOCKET;
// wait for the thread to exit
WaitForSingleObject(_hThread, INFINITE);
}
DWORD __stdcall ListenThread(void* context)
{
while (_needToExit == false)
{
SOCKET client = accept(_listenSocket, (sockaddr*)&addr, &addrSize);
if ((client == -1) || _needToExit)
{
break;
}
ProcessClient(client);
}
return 0;
}
答案 1 :(得分:1)
在这种情况下,请勿在阻塞套接字上使用accept()
。请改用非阻塞套接字。然后您可以使用select()
超时,以便您的线程可以定期检查终止条件。或者更好的是,将WSACreateEvent()
与WSASelectEvent()
一起使用。创建两个事件对象,一个用于检测客户端连接,另一个用于检测线程终止。然后,您可以使用WSAWaitForMultipleEvents()
同时等待这两个事件。在需要时使用WSASetEvent()
表示终止事件,并在发出其他事件信号时致电accept()
或WSAAccept()
。 WSAWaitForMultipleEvents()
会告诉您要采取行动的事件。