@@ -71,9 +71,14 @@ TCPTransport::TCPTransport(TCPTransport&& other) noexcept
7171 closing_(other.closing_.load()),
7272 next_req_id_(other.next_req_id_.load()),
7373 pending_responses_(std::move(other.pending_responses_)),
74- read_thread_(std::move(other.read_thread_)) {
74+ read_thread_(std::move(other.read_thread_)),
75+ inbound_pool_(std::move(other.inbound_pool_)) {
76+ // 接管方的 close_called_ 必须复位:否则其析构被幂等守卫跳过,
77+ // 被 move 进来的 read_thread_/pool 永不回收 → terminate。
78+ close_called_ = other.close_called_ ;
7579 other.socket_ = INVALID_SOCKET_VALUE ;
7680 other.connected_ = false ;
81+ other.close_called_ = true ; // 源对象已掏空,析构 Close 直通 no-op
7782}
7883
7984TCPTransport& TCPTransport::operator =(TCPTransport&& other) noexcept {
@@ -90,9 +95,14 @@ TCPTransport& TCPTransport::operator=(TCPTransport&& other) noexcept {
9095 next_req_id_ = other.next_req_id_ .load ();
9196 pending_responses_ = std::move (other.pending_responses_ );
9297 read_thread_ = std::move (other.read_thread_ );
98+ inbound_pool_ = std::move (other.inbound_pool_ );
9399
100+ // 目标接管存活连接:close_called_ 复位,析构可正常回收线程;
101+ // 源已掏空,置 true 让其析构 Close 直通 no-op。
102+ close_called_ = other.close_called_ ;
94103 other.socket_ = INVALID_SOCKET_VALUE ;
95104 other.connected_ = false ;
105+ other.close_called_ = true ;
96106 }
97107 return *this ;
98108}
@@ -279,6 +289,12 @@ void TCPTransport::Connect() {
279289}
280290
281291void TCPTransport::Close () {
292+ // 幂等:显式 Close 与析构 Close 双跑防护(曾出现 socket/线程被
293+ // 二次关闭与 join 的未定义行为)。
294+ if (close_called_) {
295+ return ;
296+ }
297+ close_called_ = true ;
282298 closing_ = true ;
283299 connected_ = false ;
284300
@@ -314,6 +330,28 @@ void TCPTransport::Close() {
314330 read_thread_.join ();
315331 }
316332
333+ // Inbound worker 池优雅停机:置 stopping + 唤醒全部 worker;worker
334+ // 引用 shared_ptr<InboundPool>,detach 后即使仍有 handler 在途,
335+ // pool 状态与 socket fd(值拷贝,send 仅得 EBADF)都保持有效——
336+ // 不会因 ~TCPTransport 而悬空。join 会阻塞在用户 handler 上,
337+ // 这里选择 detach(Go MuxConn 同款语义:不等待业务排空)。
338+ if (inbound_pool_) {
339+ {
340+ std::lock_guard<std::mutex> lock (inbound_pool_->mu );
341+ inbound_pool_->stopping = true ;
342+ inbound_pool_->sock = INVALID_SOCKET_VALUE ;
343+ inbound_pool_->handler = nullptr ;
344+ }
345+ inbound_pool_->cv .notify_all ();
346+ for (auto & t : inbound_pool_->threads ) {
347+ if (t.joinable ()) {
348+ t.detach ();
349+ }
350+ }
351+ inbound_pool_->threads .clear ();
352+ inbound_pool_.reset ();
353+ }
354+
317355 // Clear any remaining responses (should be none after signaling)
318356 std::lock_guard<std::mutex> lock (pending_mutex_);
319357 pending_responses_.clear ();
@@ -923,59 +961,78 @@ int TCPTransport::InboundWorkerCount() {
923961
924962void TCPTransport::SetInboundHandler (InboundHandler handler) {
925963 inbound_handler_ = std::move (handler);
964+ // 已启动的池同步更新 handler(重连复用同一 transport 的场景)。
965+ if (inbound_pool_) {
966+ std::lock_guard<std::mutex> lock (inbound_pool_->mu );
967+ inbound_pool_->handler = inbound_handler_;
968+ }
926969}
927970
928971void TCPTransport::DispatchInbound (uint32_t msg_id, uint32_t req_id, std::vector<uint8_t > body) {
929972 if (!inbound_handler_) {
930973 return ;
931974 }
932- // 惰性启动固定 worker 池(默认 = 硬件并发数)
933- {
934- std::lock_guard<std::mutex> lock (inbound_pool_mutex_);
935- if (!inbound_pool_started_) {
936- int workers = InboundWorkerCount ();
937- for (int i = 0 ; i < workers; ++i) {
938- inbound_workers_.emplace_back ([this ] {
939- for (;;) {
940- std::tuple<uint32_t , uint32_t , std::vector<uint8_t >> task;
941- {
942- std::unique_lock<std::mutex> lock (inbound_pool_mutex_);
943- inbound_cv_.wait (lock, [this ] { return !inbound_queue_.empty (); });
944- task = std::move (inbound_queue_.front ());
945- inbound_queue_.pop ();
975+ // 惰性启动固定 worker 池(默认 = 硬件并发数)。
976+ // worker 捕获 pool 的 shared_ptr(不捕获 this):Close/析构置 stopping
977+ // 后 worker 自行退出,pool 状态由最后一个引用负责释放——修复
978+ // 「worker for(;;) 永不退出、析构销毁被等待中的 mutex/cv」挂起。
979+ if (!inbound_pool_) {
980+ inbound_pool_ = std::make_shared<InboundPool>();
981+ inbound_pool_->handler = inbound_handler_;
982+ inbound_pool_->sock = socket_;
983+ const int workers = InboundWorkerCount ();
984+ for (int i = 0 ; i < workers; ++i) {
985+ auto pool = inbound_pool_;
986+ inbound_pool_->threads .emplace_back ([pool] {
987+ for (;;) {
988+ std::tuple<uint32_t , uint32_t , std::vector<uint8_t >> task;
989+ {
990+ std::unique_lock<std::mutex> lock (pool->mu );
991+ pool->cv .wait (lock, [&pool] { return !pool->queue .empty () || pool->stopping ; });
992+ if (pool->queue .empty ()) {
993+ return ; // stopping 且无积压:退出
946994 }
947- auto [mid, rid, tbody] = std::move (task);
948- std::vector<uint8_t > resp;
949- try {
950- resp = inbound_handler_ (mid, rid, tbody);
951- } catch (const std::exception& e) {
952- std::cerr << " [ERROR] inbound handler: " << e.what () << ' \n ' ;
953- resp.clear ();
995+ task = std::move (pool->queue .front ());
996+ pool->queue .pop ();
997+ }
998+ auto [mid, rid, tbody] = std::move (task);
999+ std::vector<uint8_t > resp;
1000+ try {
1001+ if (pool->handler ) {
1002+ resp = pool->handler (mid, rid, tbody);
9541003 }
955- WriteResponseSilently (protocol::GetResponseMsgID (mid), rid, resp);
956- inbound_queued_.fetch_sub (1 );
1004+ } catch (const std::exception& e) {
1005+ std::cerr << " [ERROR] inbound handler: " << e.what () << ' \n ' ;
1006+ resp.clear ();
9571007 }
958- });
959- }
960- inbound_pool_started_ = true ;
1008+ WriteResponseOnSocket (pool->sock , protocol::GetResponseMsgID (mid), rid, resp);
1009+ pool->queued .fetch_sub (1 );
1010+ }
1011+ });
9611012 }
9621013 }
963- int workers = InboundWorkerCount ();
964- if (inbound_queued_ .load () >= workers * 4 ) {
1014+ const int workers = InboundWorkerCount ();
1015+ if (inbound_pool_-> queued .load () >= workers * 4 ) {
9651016 // 队列满:立即回空响应,Agent 侧 failover 接管。
9661017 std::cerr << " [WARN] inbound queue full, fast-failing req_id=" << req_id << ' \n ' ;
967- WriteResponseSilently ( protocol::GetResponseMsgID (msg_id), req_id, {});
1018+ WriteResponseOnSocket (socket_, protocol::GetResponseMsgID (msg_id), req_id, {});
9681019 return ;
9691020 }
970- inbound_queued_ .fetch_add (1 );
1021+ inbound_pool_-> queued .fetch_add (1 );
9711022 {
972- std::lock_guard<std::mutex> lock (inbound_pool_mutex_ );
973- inbound_queue_ .emplace (msg_id, req_id, std::move (body));
1023+ std::lock_guard<std::mutex> lock (inbound_pool_-> mu );
1024+ inbound_pool_-> queue .emplace (msg_id, req_id, std::move (body));
9741025 }
975- inbound_cv_ .notify_one ();
1026+ inbound_pool_-> cv .notify_one ();
9761027}
9771028
978- void TCPTransport::WriteResponseSilently (uint32_t resp_msg_id, uint32_t req_id, const std::vector<uint8_t >& body) {
1029+ // WriteResponseOnSocket 向指定 fd 尽力写一帧(fd 已关闭时仅返回 EBADF,
1030+ // 不影响调用方)。静态函数:worker 持 pool->sock 值,析构后仍安全。
1031+ void TCPTransport::WriteResponseOnSocket (socket_t sock, uint32_t resp_msg_id, uint32_t req_id,
1032+ const std::vector<uint8_t >& body) {
1033+ if (sock == INVALID_SOCKET_VALUE ) {
1034+ return ;
1035+ }
9791036 try {
9801037 auto frame = protocol::NewMessage (resp_msg_id, req_id, body);
9811038 std::vector<uint8_t > wrapped (4 + frame.size ());
@@ -984,13 +1041,14 @@ void TCPTransport::WriteResponseSilently(uint32_t resp_msg_id, uint32_t req_id,
9841041 wrapped[2 ] = static_cast <uint8_t >((frame.size () >> 8 ) & 0xFF );
9851042 wrapped[3 ] = static_cast <uint8_t >(frame.size () & 0xFF );
9861043 std::memcpy (wrapped.data () + 4 , frame.data (), frame.size ());
987- ssize_t sent = send (socket_, reinterpret_cast <const char *>(wrapped.data ()),
988- static_cast <int >(wrapped.size ()), 0 );
989- (void )sent;
1044+ (void )send (sock, reinterpret_cast <const char *>(wrapped.data ()),
1045+ static_cast <int >(wrapped.size ()), 0 );
9901046 } catch (...) {
9911047 // best-effort
9921048 }
9931049}
9941050
1051+
1052+
9951053} // namespace sdk
9961054} // namespace croupier
0 commit comments