我有一个用C ++编写的Windows服务,用作侦听传入连接的TCP服务器。
我初始化服务器套接字并将accept
代码放在一个单独的线程中。 这将接受和处理传入的连接。
但是,如果服务收到STOP信号,我也需要停止这个线程。 所以我想用CreateEvent
创build一个事件对象并等待它被发送。 这个等待会发生在创build接受线程的线程中。 所以我可以使用TerminateThread
函数在接收到STOP信号时停止接受线程。
但是, MSDN说
TerminateThread是一个危险的函数,只能在极端情况下使用。
应该如何严格遵守,我的方法是否正确? 什么可能是另一种方式呢?
在Windows中,只需调用closesocket
就可以唤醒另一个线程的阻塞accept
调用。 阻塞accept
调用将返回-1,你的代码有机会通过检查你已经设置的其他退出条件(例如全局变量)来突破它所处的任何循环。
这也适用于具有close
功能的Mac(以及可能的BSD衍生物),但不适用于Linux。 这个问题更普遍的UNIX解决方案就在这里 。
下面的Windows解决方案的一些pseduo代码。
SOCKET _listenSocket; bool _needToExit = false; HANDLE _hThread; void MakelistnThreadExit() { _needToExit = true; closesocket(_listenSocket); _listenSocket = INVALID_SOCKET; // wait for the thread to exit WaitForSingleObject(_hThread, INFINITE); } DWORD __stdcall listnThread(void* context) { while (_needToExit == false) { SOCKET client = accept(_listenSocket, (sockaddr*)&addr, &addrSize); if ((client == -1) || _needToExit) { break; } ProcessClient(client); } return 0; }
在这种情况下,请不要在阻塞套接字上使用accept()
。 改为使用非阻塞套接字。 然后你可以使用select()
和超时,这样你的线程可以定期的检查终止条件。 或者,更好的方法是将WSACreateEvent()
与WSASelectEvent()
。 创建两个事件对象,一个用于检测客户端连接,另一个用于检测线程终止。 然后可以使用WSAWaitForMultipleEvents()
同时等待两个事件。 使用WSASetEvent()
在需要时发送终止事件,并在发送其他事件时调用accept()
或WSAAccept()
。 WSAWaitForMultipleEvents()
会告诉你哪个事件要执行。