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

C++ pthread_create传递vector元素为线程参数结果异常问题

问题背景

学习C++多线程编程时,尝试将vector容器的元素地址作为参数传入pthread_create接口创建线程,预期两个线程分别打印ID为99、100的执行日志,但实际运行第二个线程打印ID为0,结果不符合预期。

原实现代码如下:

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <vector>
using namespace std;
void *count(void *arg)
{
    int threadId = *((int *)arg);
    cout << "Currently thread with id " << threadId << " is executing " << endl;
    pthread_exit(NULL);
}
int main()
{
    pthread_t thread1;
    vector<int> threadId(2);
    threadId[0] = 99;
    threadId[1] = 100;
    int retVal = pthread_create(&thread1, NULL, count, (void *)&threadId[0]);
    if (retVal)
    {
        cout << "Error in creating thread with Id: " << threadId[0] << endl;
        exit(-1);
    }
    pthread_t thread2;
    retVal = pthread_create(&thread2, NULL, count, (void *)&threadId[1]);
    if (retVal)
    {
        cout << "Error in creating thread with Id: " << threadId[1] << endl;
        exit(-1);
    }
    pthread_exit(NULL);
}

实际运行输出:

Currently thread with id 99 is executing
Currently thread with id 0 is executing

问题根因

代码存在两个核心问题,直接导致参数值异常的是对象生命周期引发的野指针访问:

  • threadId是定义在main函数栈上的局部vector对象,主线程最后调用pthread_exit(NULL)终止自身时,会自动执行当前线程栈上所有局部对象的析构函数。vector析构时会释放其在堆上分配的存储元素的内存,此时两个子线程持有的参数地址指向的是已经被释放的内存,属于use-after-free的未定义行为,读到什么值都有可能,本次运行第二个参数读到0只是内存被释放后覆写的偶然结果,部分环境下甚至可能直接触发程序崩溃。
  • 额外隐患:std::cout的流插入操作不是原子操作,多线程同时无锁调用会出现输出内容穿插、错乱的问题。
修复方案

核心是保证传入子线程的参数生命周期完全覆盖子线程的执行周期,同时解决输出竞态问题,最简单的修改方式是让主线程等待两个子线程执行完毕后再退出,不要提前终止:

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <vector>
using namespace std;

// 全局互斥锁保护cout输出
pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;

void *count(void *arg)
{
    int threadId = *((int *)arg);
    pthread_mutex_lock(&print_lock);
    cout << "Currently thread with id " << threadId << " is executing " << endl;
    pthread_mutex_unlock(&print_lock);
    pthread_exit(NULL);
}
int main()
{
    pthread_t thread1;
    vector<int> threadId(2);
    threadId[0] = 99;
    threadId[1] = 100;
    int retVal = pthread_create(&thread1, NULL, count, (void *)&threadId[0]);
    if (retVal)
    {
        cout << "Error in creating thread with Id: " << threadId[0] << endl;
        exit(-1);
    }
    pthread_t thread2;
    retVal = pthread_create(&thread2, NULL, count, (void *)&threadId[1]);
    if (retVal)
    {
        cout << "Error in creating thread with Id: " << threadId[1] << endl;
        exit(-1);
    }
    // 等待两个子线程执行完毕,保证vector生命周期覆盖子线程执行全程
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    // 子线程全部执行完再退出主线程
    pthread_exit(NULL);
}

其他可选的生命周期保障方式:

  • 将存储线程ID的vector定义为全局变量,生命周期持续到进程退出
  • 用new动态分配每个线程的参数内存,子线程执行结束后自行delete释放
  • 如果编写纯C代码,建议直接使用C11提供的std::thread,可以通过值传递参数避免生命周期问题,不需要手动处理指针传参的隐患。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 07:27:16