Boost.Asio UDP服务器构造时do_use_service中断问题排查与修改咨询
问题描述
调试时程序在调用service_registry.ipp中的execution_context::service* service_registry::do_use_service()函数时抛出异常,最终中断在win_mutex.hpp的以下代码处:
void lock() { ::EnterCriticalSection(&crit_section_); }
需要解决:
- 中断的原因是什么?
- 如何修改UDPServer类?
- 将
io_context作为UDPServer类的成员,仅传入主机和端口即可使用对象,这种方式是否可行?
现有代码
头文件(UdpServerByUsingBoostAsio.h)
#ifndef UDPSERVER_H #define UDPSERVER_H #include <boost/asio.hpp> #include <string> namespace util { class UDPServer : public std::enable_shared_from_this<UDPServer> { public: enum { UDP_PORT = 18400 }; UDPServer(const std::string& host, short port); ~UDPServer(); void start_receive(); //void setObserver(std::weak_ptr<WebSocket::Observer> observer) noexcept; void start(); private: boost::asio::ip::udp::socket socket_; boost::asio::io_context io_context_; // 接受ip和端口 boost::asio::ip::udp::endpoint sender_endpoint_; // 设置一个指针,参考util::WebSocket //std::weak_ptr<WebSocket::Observer> observer_; enum { max_length = 1024 }; char data_[max_length]; bool start_ = false; }; } // namespace util #endif
.cpp文件(UdpServerByUsingBoostAsio.cpp)
#include "UdpServerByUsingBoostAsio.h" namespace util { UDPServer::UDPServer(const std::string& host, short port) :io_context_(),socket_(io_context_, boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(host), port)) { printf("debug:UDPServer Constructor"); //start_receive(); start_receive(); io_context_.run(); } UDPServer::~UDPServer() { socket_.close(); } void UDPServer::start_receive() { printf("debug:UDPServer start_receive"); socket_.async_receive_from(boost::asio::buffer(data_, max_length), sender_endpoint_, [this](boost::system::error_code error, std::size_t bytes_recvd) { printf("debug:UDPServer handle_receive"); if (!error) { printf(" Received message from %s,%d,%s", sender_endpoint_.address().to_string().c_str(), sender_endpoint_.port(), data_); start_receive(); } else { printf("error:UDPServer handle_receive,ec_msg:%s", error.message().c_str()); }}); } void UDPServer::start() { start_ = true; //start_receive(); //io_context_.run(); } } // namespace util
main.cpp
#include <iostream> #include <boost/asio.hpp> #include "UdpServerByUsingBoostAsio.h" #include <memory> #include <string> #include <cstdio> #include <thread> using namespace std; int main() { try { shared_ptr<std::thread> netAccess_ = std::make_shared<std::thread>([&] { std::shared_ptr<util::UDPServer> ptr1 = std::make_shared<util::UDPServer>("127.0.0.1", util::UDPServer::UDP_PORT); ptr1->start(); }); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } printf("%-> modelId(%s)", "caiji", "jiuzhe"); return 0; }
问题分析与解决方案
中断原因
- io_context运行时机错误:构造函数中直接调用
io_context_.run(),导致UDPServer对象的构造过程阻塞,而主线程很快退出,创建服务器的线程被销毁,引发io_context内部服务注册表的临界区访问异常。 - 线程生命周期管理混乱:
main中创建的线程是局部shared_ptr,主线程执行完后线程对象被销毁,服务器线程可能还在运行,引发资源访问冲突。 - 悬空引用风险:线程lambda使用
[&]捕获外部变量,主线程退出后引用失效,可能间接导致io_context内部状态异常。
修改UDPServer类的方案
核心思路是封装io_context的生命周期,让服务器启动、停止逻辑可控,避免构造阶段阻塞。
修改后的头文件
#ifndef UDPSERVER_H #define UDPSERVER_H #include <boost/asio.hpp> #include <string> #include <thread> #include <atomic> namespace util { class UDPServer : public std::enable_shared_from_this<UDPServer> { public: enum { UDP_PORT = 18400 }; UDPServer(const std::string& host, short port); ~UDPServer(); void start(); void stop(); private: void start_receive(); boost::asio::ip::udp::socket socket_; boost::asio::io_context io_context_; boost::asio::ip::udp::endpoint sender_endpoint_; enum { max_length = 1024 }; char data_[max_length]; std::atomic<bool> running_; std::thread io_thread_; }; } // namespace util #endif
修改后的.cpp文件
#include "UdpServerByUsingBoostAsio.h" namespace util { UDPServer::UDPServer(const std::string& host, short port) : socket_(io_context_, boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(host), port)), running_(false) { printf("debug:UDPServer Constructor\n"); } UDPServer::~UDPServer() { stop(); } void UDPServer::start() { if (running_.exchange(true)) return; start_receive(); io_thread_ = std::thread([this] { printf("debug:io_context running\n"); io_context_.run(); printf("debug:io_context stopped\n"); }); } void UDPServer::stop() { if (!running_.exchange(false)) return; socket_.close(); io_context_.stop(); if (io_thread_.joinable()) { io_thread_.join(); } } void UDPServer::start_receive() { printf("debug:UDPServer start_receive\n"); socket_.async_receive_from(boost::asio::buffer(data_, max_length), sender_endpoint_, [self = shared_from_this()](boost::system::error_code error, std::size_t bytes_recvd) { printf("debug:UDPServer handle_receive\n"); if (!error && self->running_) { printf(" Received message from %s:%d, data:%.*s\n", self->sender_endpoint_.address().to_string().c_str(), self->sender_endpoint_.port(), static_cast<int>(bytes_recvd), self->data_); self->start_receive(); } else if (error) { printf("error:UDPServer handle_receive, ec_msg:%s\n", error.message().c_str()); } }); } } // namespace util
修改后的main.cpp
#include <iostream> #include <boost/asio.hpp> #include "UdpServerByUsingBoostAsio.h" #include <memory> #include <string> #include <cstdio> #include <thread> #include <chrono> using namespace std; int main() { try { std::shared_ptr<util::UDPServer> ptr1 = std::make_shared<util::UDPServer>("127.0.0.1", util::UDPServer::UDP_PORT); ptr1->start(); // 保持主线程运行,避免程序提前退出 printf("Server running, press Enter to exit...\n"); getchar(); ptr1->stop(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << std::endl; } return 0; }
关于io_context作为类成员的可行性
完全可行,这种方式完美符合面向对象的封装原则,将网络相关资源(io_context、socket)都封装在UDPServer内部,用户只需传入主机和端口即可创建并使用服务器,无需关心底层网络循环的实现,使用体验更简洁安全。修改后的代码正是采用这种设计。
内容的提问来源于stack exchange,提问作者sleepy2con
相关产品推荐
相关产品推荐

