C++多线程Socket编程多并发时accept触发Fatal program exit requested异常
崩溃核心原因
1. 局部std::thread析构触发程序强制终止
主循环块作用域内创建的std::thread t,既未调用join()等待执行完成,也未调用detach()解绑线程与对象。
C++标准规定:std::thread对象析构时,若仍处于可接合(joinable)状态,程序会直接触发std::terminate,抛出Fatal program exit requested致命异常。
该问题触发时机与现象完全匹配:第一次循环创建的t在循环体执行完毕、准备进入第二次迭代时被析构,调试器可能因栈帧偏移将异常落点标记到下一次循环的accept调用行。
2. 其他隐性风险(非本次崩溃主因,但会引发后续异常)
- 全局变量
numConn在主线程、工作线程间无同步读写,存在竞态条件 - 线程函数中直接对二进制图像数据执行
printf(recievingBuffer)输出,若数据无\0终止符会引发内存越界 serverInitilization函数中iResult、wsaData、hints、result均为值传递,函数内的修改无法同步到主函数原始变量,属于逻辑错误(本次因Winsock为进程级初始化未暴露问题,但会埋下隐患)- 工作线程中使用模态
MessageBox会阻塞线程,不适配服务端运行场景
修正方案
解决核心崩溃问题
两种合规方案二选一:
- 方案1:线程detach独立运行
创建线程后新增解绑语句:thread t(recThread, ClientSocket); t.detach(); cout << "Thread started. Back to listening...\n"; - 方案2:维护线程列表统一管理
避免detach带来的资源失控问题,用线程安全容器存储已创建的工作线程,定期清理已结束的线程:// 全局定义 std::vector<std::thread> workerThreads; std::mutex threadMutex; // 主循环内创建线程时替换原有逻辑 { std::lock_guard<std::mutex> lock(threadMutex); workerThreads.emplace_back(recThread, ClientSocket); // 每轮循环清理已终止的线程 for (auto it = workerThreads.begin(); it != workerThreads.end();) { if (it->joinable()) { // 可根据线程退出标记判断是否可join,此处为简化示例 it->join(); it = workerThreads.erase(it); } else { ++it; } } }
修复其他隐性问题
- 用原子类型替换
numConn,消除竞态条件:std::atomic<int> numConn{0}; - 移除线程函数中针对二进制接收数据的
printf(recievingBuffer)语句,仅保留字节数打印用于调试 - 调整
serverInitilization参数为引用传递,避免值传递导致的逻辑不一致:void serverInitilization(int& iResult, WSADATA& socketData, struct addrinfo& hints, struct addrinfo*& result, SOCKET& ClientSocket, SOCKET& ListenSocket) - 移除工作线程中的
MessageBox弹窗,连接断开时直接关闭socket、退出线程即可
内容的提问来源于stack exchange,提问作者Omar Hammad
相关产品推荐
相关产品推荐

