У меня есть служба Windows, написанная на C ++, которая функционирует как TCP-сервер, прослушивающий входящие соединения.
Я инициализировал сокет сервера и поставил accept
Код в отдельном потоке. Это примет и обработает входящие соединения.
Однако мне также нужно остановить этот поток в случае, если служба получает сигнал STOP. Поэтому я подумал о создании объекта события, используя CreateEvent
и ждет, пока это будет сигнализировано. Это ожидание будет происходить в потоке, который создает поток принятия. Так что я мог бы использовать TerminateThread
функция для остановки потока приема при получении сигнала STOP.
Тем не мение, MSDN Говорит, что
TerminateThread — опасная функция, которую следует использовать только в самых крайних случаях.
Насколько строго следует этому следовать, и правильный ли мой подход? Что может быть еще один способ сделать это?
В Windows вы можете разбудить блокировку accept
звонить из другого потока просто позвонив closesocket
, Блокировка accept
call вернет -1, и ваш код сможет выйти из цикла, в котором он находится, проверив некоторые другие условия выхода, которые вы уже установили (например, глобальная переменная)
Это также работает с Mac (и, вероятно, производными BSD) с close
функция, но не Linux. Более универсальное решение этой проблемы в UNIX Вот.
Некоторые псевдо-код для решения Windows ниже.
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;
}
В этой ситуации не используйте accept()
на розетке блокировки. Вместо этого используйте неблокирующий сокет. Тогда вы можете использовать select()
с таймаутом, чтобы ваша нить могла периодически проверять условие завершения. Или лучше использовать WSACreateEvent()
с WSASelectEvent()
, Создайте два объекта события, один для обнаружения клиентских подключений и один для обнаружения завершения потока. Вы можете использовать WSAWaitForMultipleEvents()
ждать обоих событий одновременно. использование WSASetEvent()
сообщить о событии завершения при необходимости и вызвать accept()
или же WSAAccept()
всякий раз, когда другое событие сигнализируется. WSAWaitForMultipleEvents()
скажет вам, на каком событии действовать.