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

使用pthread未输出预期值:线程读取共享变量值异常原因

多线程执行顺序导致的变量值意外问题解析

首先,先把你的代码和遇到的问题理清楚:

你的C语言多线程代码:

void *thread(void *vargp) { 
    int *ptr = (int*)vargp; 
    printf("vargp = %p, *vargp = %d\n",vargp, *(int*)vargp); 
    pthread_exit((void*)*ptr); 
} 

void *thread2(void *vargp) { 
    int *ptr = (int*)vargp; 
    *ptr = 0; 
    pthread_exit((void*)31); 
} 

int main(){ 
    int i = 42; 
    pthread_t tid, tid2; 
    pthread_create(&tid, NULL, thread, (void*)&i); 
    printf("i = %d, &i = %p\n", i, &i); 
    pthread_create(&tid2, NULL, thread2, (void*)&i); 
    pthread_join(tid, (void**)&i); 
    pthread_join(tid2, NULL); 
    printf("at the end i = %d\n",i); 
}

你预期最后一行输出at the end i = 42,但实际得到的输出是:

i = 42, &i = 0x7ffcf3b65c4c 
vargp = 0x7ffcf3b65c4c, *vargp = 0 
0 

你疑惑的是:明明vargp的地址和i的地址完全一致,为什么读取到的*vargp是0而不是42?

核心问题:线程调度的不确定性

咱们得先明确一个关键知识点:操作系统对线程的调度顺序是完全没有保证的——哪怕你先调用pthread_create创建了thread,也不代表它会比后创建的thread2先执行。

在你的这次运行中,实际的执行顺序是这样的:

  1. 主线程初始化i=42,调用pthread_create创建thread,但操作系统并没有立刻让thread开始运行,主线程继续往下走。
  2. 主线程执行printf,输出了i的初始值42和它的地址。
  3. 主线程创建thread2,这时候操作系统选择先调度thread2执行:thread2直接把i的值改成了0,然后退出。
  4. 直到这时候,操作系统才调度thread线程执行,此时i已经被thread2改成0了,所以*vargp读取到的自然是0。
  5. 最后主线程调用pthread_join(tid, (void**)&i),把thread线程的退出值(也就是0,因为*ptr当时是0)赋值给了i,所以最后printf输出的0其实是这个退出值(刚好和thread2修改的结果一致)。

额外补充:关于线程退出值的赋值

这里还要提一下pthread_join的第二个参数:你把&i强转成(void**)传递进去,意味着pthread_join会把线程的退出指针值转换成整数赋值给i。哪怕thread2没修改i,只要thread返回的是42,i最后也会是42;但在这次运行中,thread返回的是0,所以i最终被设置为0。

如何得到你预期的输出?

如果想保证thread先读取到i的初始值42,你需要用同步机制来控制线程的执行顺序,比如互斥锁(pthread_mutex_t):

#include <pthread.h>
#include <stdio.h>

pthread_mutex_t mutex;

void *thread(void *vargp) { 
    pthread_mutex_lock(&mutex);
    int *ptr = (int*)vargp; 
    printf("vargp = %p, *vargp = %d\n",vargp, *(int*)vargp); 
    pthread_exit((void*)*ptr); 
} 

void *thread2(void *vargp) { 
    pthread_mutex_lock(&mutex);
    int *ptr = (int*)vargp; 
    *ptr = 0; 
    pthread_exit((void*)31); 
} 

int main(){ 
    pthread_mutex_init(&mutex, NULL);
    // 先上锁,让thread2必须等thread解锁后才能执行
    pthread_mutex_lock(&mutex);
    
    int i = 42; 
    pthread_t tid, tid2; 
    pthread_create(&tid, NULL, thread, (void*)&i); 
    printf("i = %d, &i = %p\n", i, &i); 
    pthread_create(&tid2, NULL, thread2, (void*)&i); 
    
    pthread_join(tid, (void**)&i); 
    pthread_mutex_unlock(&mutex); // 解锁允许thread2执行
    pthread_join(tid2, NULL); 
    printf("at the end i = %d\n",i); 
    
    pthread_mutex_destroy(&mutex);
}

这样就能确保thread先执行并读取到i=42,之后thread2才会修改i,最后i会被pthread_join赋值为42,输出符合你的预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:19:37