我目前正在开发简单的HTTP服务器。我使用来自C ++ 11的Winsock和标准线程。对于每个连接(接受)的客户端,都会创建新线程。
std::map<SOCKET, std::thread> threads;
bool server_running = true;
while(server_running) {
SOCKET client_socket;
client_socket = accept(listen_socket, NULL, NULL);
if(client_socket == INVALID_SOCKET) {
// some error handling
}
threads[client_socket] = std::thread(clientHandler, client_socket);
}
clientHandler
函数通常看起来像这样:
while(1) {
while(!all_data_received) {
bytes_received = recv(client_socket, recvbuf, recvbuflen, 0);
if(bytes_received > 0) {
// do something
} else {
goto client_cleanup;
}
}
// do something
}
client_cleanup: // we also get here when Connection: close was received
closesocket(client_socket);
在这里我们遇到了我的问题 - 如何处理已结束但尚未与主线程连接的所有线程,并且threads
地图中仍然存在对它们的引用?
最简单的解决方案可能是经常迭代threads
(e.q。来自另一个线程?)并加入并删除那些返回的。
请分享您的专业知识。 :)
<子> PS。是的,我知道线程池模式。我没有在我的应用程序中使用它(无论好坏)。我正在寻找有关我目前架构的答案。
答案 0 :(得分:2)
简单的解决方案?启动线程后只需detach()
。这意味着一旦线程终止,资源将被清理,您不需要保留std::map<SOCKET, std::thread> threads
。
std::thread(clientHandler, client_socket).detach();
否则创建一个线程安全的LIFO队列,在清理期间将套接字推送到它。
然后在主循环中交替检查accept
和该队列,当队列中有套接字时,对队列中的每个套接字执行threads.erase(socket);
。
但是,如果你这样做,那么你也可以将LIFO推向另一个方向并使用线程池。