c – 如何从父插槽中删除子对象?可能会提升:: asio特定
发布时间:2020-12-16 06:55:20 所属栏目:百科 来源:网络整理
导读:我编写了一个网络服务器类来维护一组std ::网络客户端.网络客户端在断开连接时向网络服务器发出信号(通过boost :: bind).当网络客户端断开连接时,需要从Set中删除客户端实例并最终删除.我认为这是一种常见的模式,但我遇到的问题可能是,也可能不是ASIO特有的.
我编写了一个网络服务器类来维护一组std ::网络客户端.网络客户端在断开连接时向网络服务器发出信号(通过boost :: bind).当网络客户端断开连接时,需要从Set中删除客户端实例并最终删除.我认为这是一种常见的模式,但我遇到的问题可能是,也可能不是ASIO特有的.
我试图减少相关代码: /** NetworkServer.hpp **/ class NetworkServices : private boost::noncopyable { public: NetworkServices(void); ~NetworkServices(void); private: void run(); void onNetworkClientEvent(NetworkClientEvent&); private: std::set<boost::shared_ptr<const NetworkClient>> clients; }; /** NetworkClient.cpp **/ void NetworkServices::run() { running = true; boost::asio::io_service::work work(io_service); //keeps service running even if no operations // This creates just one thread for the boost::asio async network services boost::thread iot(boost::bind(&NetworkServices::run_io_service,this)); while (running) { boost::system::error_code err; try { tcp::socket* socket = new tcp::socket(io_service); acceptor->accept(*socket,err); if (!err) { NetworkClient* networkClient = new NetworkClient(io_service,boost::shared_ptr<tcp::socket>(socket)); networkClient->networkClientEventSignal.connect(boost::bind(&NetworkServices::onNetworkClientEvent,this,_1)); clients.insert(boost::shared_ptr<NetworkClient>(networkClient)); networkClient->init(); //kicks off 1st asynch_read call } } // etc... } } void NetworkServices::onNetworkClientEvent(NetworkClientEvent& evt) { switch(evt.getType()) { case NetworkClientEvent::CLIENT_ERROR : { boost::shared_ptr<const NetworkClient> clientPtr = evt.getClient().getSharedPtr(); // ------ THIS IS THE MAGIC LINE ----- // If I keep this,the io_service hangs. If I comment it out,// everything works fine (but I never delete the disconnected NetworkClient). // If actually deleted the client here I might expect problems because it is the caller // of this method via boost::signal and bind. However,The clientPtr is a shared ptr,and a // reference is being kept in the client itself while signaling,so // I would the object is not going to be deleted from the heap here. That seems to be the case. // Never-the-less,this line makes all the difference,most likely because it controls whether or not the NetworkClient ever gets deleted. clients.erase(clientPtr); //I should probably put this socket clean-up in NetworkClient destructor. Regardless by doing this,// I would expect the ASIO socket stuff to be adequately cleaned-up after this. tcp::socket& socket = clientPtr->getSocket(); try { socket.shutdown(boost::asio::socket_base::shutdown_both); socket.close(); } catch(...) { CommServerContext::error("Error while shutting down and closing socket."); } break; } default : { break; } } } /** NetworkClient.hpp **/ class NetworkClient : public boost::enable_shared_from_this<NetworkClient>,Client { NetworkClient(boost::asio::io_service& io_service,boost::shared_ptr<tcp::socket> socket); virtual ~NetworkClient(void); inline boost::shared_ptr<const NetworkClient> getSharedPtr() const { return shared_from_this(); }; boost::signal <void (NetworkClientEvent&)> networkClientEventSignal; void onAsyncReadHeader(const boost::system::error_code& error,size_t bytes_transferred); }; /** NetworkClient.cpp - onAsyncReadHeader method called from io_service.run() thread as result of an async_read operation. Error condition usually result of an unexpected client disconnect.**/ void NetworkClient::onAsyncReadHeader( const boost::system::error_code& error,size_t bytes_transferred) { if (error) { //Make sure this instance doesn't get deleted from parent/slot deferencing //Alternatively,somehow schedule for future delete? boost::shared_ptr<const NetworkClient> clientPtr = getSharedPtr(); //Signal to service that this client is disconnecting NetworkClientEvent evt(*this,NetworkClientEvent::CLIENT_ERROR); networkClientEventSignal(evt); networkClientEventSignal.disconnect_all_slots(); return; } 我认为从插槽处理程序中删除客户端是不安全的,因为函数返回将是… undefined? (有趣的是,它似乎并没有让我感到沮丧.)所以我使用了boost:shared_ptr和shared_from_this来确保客户端不会被删除,直到所有插槽都被发出信号.但这似乎并不重要. 我相信这个问题并不是针对ASIO的,但问题在于使用ASIO时会以一种特殊的方式出现.我有一个执行io_service.run()的线程.所有ASIO读/写操作都是异步执行的.一切正常,多个客户端连接/断开连接除了我从上面的代码Set中删除我的客户端对象.如果我删除了我的客户端对象,io_service似乎在内部死锁,除非我启动另一个线程,否则不会执行进一步的异步操作.我试着/捕获io_service.run()调用并且无法检测到任何错误. 问题: >是否有从父插槽中删除子对象(也是信号发射器)的最佳做法? 解决方法
您可以将weak_ptr存储在集合中,因此shared_ptr将仅由asio保留并在断开连接时自动释放.从~Client()中的set中删除相应的weak_ptr
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |