Boost Asio客户端服务端程序崩溃求助:std::system_error死锁避免
解决服务端线程join时的资源死锁异常
嘿,这个问题的根源一眼就能看穿——你在让线程尝试等待自己结束,这直接触发了系统的资源死锁检测,所以抛出了Resource deadlock avoided异常。
问题具体分析
看你的Service类代码逻辑:
- 在
StartHandligClient方法中,你创建了一个新线程,这个线程的执行体就是HandleClient函数,同时把这个线程的指针存在了m_thread成员变量里。 - 然后在
HandleClient函数的末尾,你调用了m_thread->join()——但此时m_thread指向的就是当前正在运行HandleClient的线程!线程等待自己结束,这是不可能完成的操作,系统自然会抛出死锁异常。
另外还有个潜在问题:你在HandleClient里直接delete this,这种手动管理内存的方式很容易导致悬空指针或者内存泄漏,建议用智能指针来管理Service实例。
修复方案
- 移除自join的代码:删掉
HandleClient里的m_thread->join()调用,线程完全不需要等待自己结束。 - 用智能指针管理Service生命周期:把
new Service改成std::make_shared<Service>,让线程结束后自动释放资源,彻底避免手动delete带来的风险。
修改后的服务端核心代码
#include <boost/asio.hpp> #include <thread> #include <atomic> #include <memory> #include <iostream> using namespace boost; class Service { public: Service(){} void StartHandligClient( std::shared_ptr<asio::ip::tcp::socket> sock) { // 不需要把线程存在成员变量,直接detach让线程后台运行 std::thread([this, sock]() { HandleClient(sock); }).detach(); } private: void HandleClient(std::shared_ptr<asio::ip::tcp::socket> sock) { while(1) { try { asio::streambuf request; std::cout << "Waiting to read \n"; asio::read_until(*sock.get(), request, '\n'); std::string s( (std::istreambuf_iterator<char>(&request)), std::istreambuf_iterator<char>() ); std::cout << "Server got : " << s << "\n"; // Emulate request processing. int i = 0; while (i != 1000000) i++; std::this_thread::sleep_for( std::chrono::milliseconds(500)); // Sending response. std::string response = "Response\n"; asio::write(*sock.get(), asio::buffer(response)); } catch (system::system_error &e) { boost::system::error_code ec = e.code(); if(ec == asio::error::eof) { std::cout << "Breaking loop \n"; break; } std::cout << "Error occured! Error code = " << e.code() << ". Message: " << e.what(); } } // 移除原有的join和delete this,线程结束后自动销毁资源 } // 删掉不必要的m_thread成员变量 }; class Acceptor { public: Acceptor(asio::io_service& ios, unsigned short port_num) : m_ios(ios), m_acceptor(m_ios, asio::ip::tcp::endpoint( asio::ip::address_v4::any(), port_num)) { m_acceptor.listen(); } void Accept() { std::cout << "Server Accept() \n" << std::flush; std::shared_ptr<asio::ip::tcp::socket> sock(new asio::ip::tcp::socket(m_ios)); std::cout << "BEFORE calling acceptor's accept function \n" << std::flush; m_acceptor.accept(*sock.get()); std::cout << "AFTER calling acceptor's accept function \n" << std::flush; // 用shared_ptr管理Service实例,避免手动delete auto service = std::make_shared<Service>(); service->StartHandligClient(sock); } void close() { std::cout << "Inside Acceptor.close() \n" << std::flush; m_acceptor.close(); } private: asio::io_service& m_ios; asio::ip::tcp::acceptor m_acceptor; }; // Server类保持原有逻辑不变 class Server { public: Server() : m_stop(false) {} void Start(unsigned short port_num) { m_thread.reset(new std::thread([this, port_num]() { Run(port_num); })); } void Stop() { m_stop.store(true); m_thread->join(); } private: void Run(unsigned short port_num) { Acceptor acc(m_ios, port_num); while (!m_stop.load()) { std::cout << "Server accept\n" << std::flush; acc.Accept(); } acc.close(); } std::unique_ptr<std::thread> m_thread; std::atomic<bool> m_stop; asio::io_service m_ios; }; int main() { unsigned short port_num = 3333; try { Server srv; srv.Start(port_num); std::this_thread::sleep_for(std::chrono::seconds(4)); srv.Stop(); } catch (system::system_error &e) { std::cout << "Error occured! Error code = " << e.code() << ". Message: " << e.what(); } return 0; }
额外说明
- 我们把线程改成
detach(),让它在后台独立运行,不需要主线程等待它结束,这更符合服务端并发处理客户端请求的场景。 - 用
std::shared_ptr<Service>管理服务实例,当线程结束后,智能指针会自动释放资源,彻底避免了手动delete带来的内存泄漏或悬空指针问题。 - 现在服务端可以正常处理客户端请求,当
Server::Stop()被调用时,会正常关闭acceptor,不会再出现死锁异常,能和客户端一样正常退出。
内容的提问来源于stack exchange,提问作者Nishant Sharma
相关产品推荐
相关产品推荐

