You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++多线程程序意外终止求助:多设备消息发送未完成

问题排查与修复方案

你的程序莫名终止的核心原因有几个,逐一分析并给出修复:

1. 迭代器引用捕获导致的未定义行为

在async的lambda中,你用[&]捕获了循环迭代器it的引用,但循环过程中it会被不断递增,线程启动后很可能it已经指向mapDevtoMessage.end(),此时访问it->second或it->first会触发未定义行为,直接导致程序崩溃或异常终止。

修复方案:捕获迭代器的副本,或者直接捕获当前循环的元素值:

vector<future<void>> futures;
// 用范围for循环更安全,避免迭代器引用问题
for(auto& pair : mapDevtoMessage){
  futures.push_back(async(launch::async, [&vec=pair.second, name=pair.first]{ 
    send_messages(vec, name);
  }));
  std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
for(auto &its : futures){
  its.wait();
}

如果坚持使用迭代器循环,可捕获当前元素的副本:

vector<future<void>> futures;
auto it = mapDevtoMessage.begin();
for(; it != mapDevtoMessage.end(); ++it){
  auto current_pair = *it; // 复制当前元素,避免引用失效
  futures.push_back(async(launch::async, [&]{ 
    send_messages(current_pair.second, current_pair.first);
  }));
  std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
for(auto &its : futures){
  its.wait();
}

2. 未处理的错误引发程序终止

当socket()、connect()调用失败时,你的代码仅打印错误但继续执行后续逻辑:

  • 若connect()失败,后续调用send()时会传入无效的文件描述符,触发SIGPIPE信号,默认信号处理逻辑是直接终止程序。
  • 未检查send()的返回值,发送失败时也会引发异常或未定义行为。

修复方案:错误发生后立即退出函数,避免后续无效操作:

void send_messages (vector<string>& vec, string name){
  mtx.lock();
  PORT++;
  int current_port = PORT; // 保存当前端口,避免PORT后续变化影响日志
  mtx.unlock();

  int sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0) {
    mtx.lock();
    printf("Socket creation error for device %s\n", name.c_str());
    mtx.unlock();
    return;
  }

  struct sockaddr_in serv_addr{};
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(current_port);
  if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
    mtx.lock();
    printf("Invalid address for device %s, port %d\n", name.c_str(), current_port);
    mtx.unlock();
    close(sock);
    return;
  }

  // connect返回0表示成功,失败返回-1,无需将返回值赋值给client_fd
  if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
    mtx.lock();
    printf("Connection Failed for device %s, port %d\n", name.c_str(), current_port);
    mtx.unlock();
    close(sock);
    return;
  }

  for(auto &i : vec){
    string val = hexToASCII(i);
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    // 用字符串实际长度代替硬写的100,避免内存越界
    ssize_t send_len = send(sock, val.c_str(), val.size(), 0);
    mtx.lock();
    if(send_len < 0){
      printf("Send failed for message %s from %s\n", i.c_str(), name.c_str());
    } else {
      printf("Message %s from %s sent (port %d)\n", i.c_str(), name.c_str(), current_port);
    }
    mtx.unlock();
    if(send_len < 0) break; // 发送失败则终止后续发送
  }

  close(sock); // 关闭通信socket
}

3. PORT变量的边界检查

服务器仅开放10000个端口,需确保PORT递增不会超出范围,否则后续connect必然失败,甚至可能重复使用端口。

修复方案:添加PORT边界检查:

mtx.lock();
// 假设服务器起始端口为START_PORT,最大端口为START_PORT+9999
const int START_PORT = 8000;
const int MAX_PORT = START_PORT + 9999;
if(PORT > MAX_PORT){
  mtx.unlock();
  mtx.lock();
  printf("No available ports for device %s\n", name.c_str());
  mtx.unlock();
  return;
}
PORT++;
int current_port = PORT;
mtx.unlock();

4. SIGPIPE信号处理(可选)

若不想因send失败触发程序终止,可在程序启动时忽略SIGPIPE信号:

#include <signal.h>

int main(){
  signal(SIGPIPE, SIG_IGN); // 忽略SIGPIPE信号,send失败仅返回-1
  // ... 其他初始化代码
}

内容的提问来源于stack exchange,提问作者malviska

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 02:30:57