C语言多线程代码问题:打印顺序异常且程序挂起
多线程C程序的输出顺序与挂起问题修复
问题分析
1. 输出顺序混乱+线程号错误
- 输出顺序不符:主线程打印
a的操作和线程打印信息的操作没有同步约束,线程被创建后可能立即被调度执行,抢在主线程的printf之前输出内容。 - 线程号重复/错误:传递给线程的是循环变量
i的地址,主线程循环会持续修改i的值,线程读取*(int*)data时,拿到的往往是i更新后的最新值,而非创建线程时的i。
2. 程序挂起无法终止
主线程循环中,i初始为0,先执行i++变为1,再调用pthread_create(&array[i], ...),也就是往array[1]到array[10]写入线程ID。但数组array大小为N=10,下标范围是0-9,array[10]属于数组越界,会触发非法内存访问。后续pthread_join遍历i=0到9时,array[0]从未被初始化,调用pthread_join未初始化的线程ID会触发未定义行为,导致程序挂起。
修复后的代码
#include <stdio.h> #include <pthread.h> #include <stdlib.h> #define N 10 static int a = 0; pthread_mutex_t mut_a; pthread_mutex_t mut_print; // 用于传递线程独立数据的结构体 typedef struct { int thread_num; } ThreadData; void *dummy(void *data) { ThreadData *td = (ThreadData*)data; // 互斥保护变量a的递增操作 pthread_mutex_lock(&mut_a); a++; pthread_mutex_unlock(&mut_a); // 互斥同步输出,保证主线程先打印a的值 pthread_mutex_lock(&mut_print); printf("In the dummy function.. thread %d \n", td->thread_num); pthread_mutex_unlock(&mut_print); free(td); return NULL; // 线程函数必须返回void*类型 } int main() { int ret; pthread_t array[N]; pthread_mutex_init(&mut_a, NULL); pthread_mutex_init(&mut_print, NULL); for (int i = 0; i < N; i++) { // 为每个线程分配独立的数据结构,避免共享循环变量 ThreadData *td = malloc(sizeof(ThreadData)); if (!td) { perror("malloc failed"); return 1; } td->thread_num = i + 1; // 线程号从1到10 // 正确使用数组下标,避免越界 ret = pthread_create(&array[i], NULL, dummy, td); if (ret != 0) { printf("Error creating thread %d, code %d.. \n", i+1, ret); free(td); // 清理已创建的线程 for (int j = 0; j < i; j++) { pthread_join(array[j], NULL); } pthread_mutex_destroy(&mut_a); pthread_mutex_destroy(&mut_print); return 1; } // 互斥同步输出,确保先打印a的值 pthread_mutex_lock(&mut_print); printf("a value is: %d\n", a); pthread_mutex_unlock(&mut_print); } // 等待所有线程执行完毕 for (int i = 0; i < N; i++) { pthread_join(array[i], NULL); } pthread_mutex_destroy(&mut_a); pthread_mutex_destroy(&mut_print); return 0; }
关键修改点
- 解决数组越界:调整循环逻辑,直接使用
i从0到9作为数组下标,确保array[i]都被正确赋值。 - 避免共享变量问题:用动态分配的
ThreadData结构体为每个线程传递独立的线程号,不再传递循环变量的地址。 - 同步输出顺序:新增
mut_print互斥锁,约束主线程和线程的输出操作,保证先打印a的值,再打印线程信息。 - 完善资源清理:线程函数中释放动态分配的内存,创建线程失败时清理已创建的线程和互斥锁。
内容的提问来源于stack exchange,提问作者toor_49
相关产品推荐
相关产品推荐

