为何全局变量n_segments在多线程环境下值不一致?
问题
我编写了一个C语言多线程程序,声明了若干全局变量并创建子线程进行交互。主线程中为全局变量n_segments赋值为81,但在子线程的segment_handler函数中读取到的n_segments值却为0。既然全局变量本应在多线程间共享,请问为何会出现这种值不一致的情况?
程序代码
#include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <getopt.h> #include <fcntl.h> #include <assert.h> #include <pthread.h> #include <sys/stat.h> #include <sys/mman.h> #include <sys/sysinfo.h> #include <sys/types.h> #include <unistd.h> #include <sys/syscall.h> typedef struct zip_seg zip_seg_t; typedef struct stat stat_t; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; char **file_ptr; char *segment_ptr; stat_t *stat_buf; struct zip_seg { char *data; size_t size; }; int index_cur_file = 0, index_cur_segment = 0; int n_segments; int total_segments_cur_file = 0; int segment_size = 100; zip_seg_t *zip_list; void* segment_handler() { int size; pid_t x = syscall(__NR_gettid); //printf("ID %d getting in...\n", x); while(1) { pthread_mutex_lock(&lock); if(index_cur_segment >= n_segments) { pthread_mutex_unlock(&lock); break; } if((total_segments_cur_file * segment_size) < stat_buf[index_cur_file].st_size) { size = stat_buf[index_cur_file].st_size - (total_segments_cur_file * segment_size); index_cur_file++; total_segments_cur_file = 0; segment_ptr = file_ptr[index_cur_file]; } else { size = segment_size; total_segments_cur_file++; segment_ptr += size; } int i = index_cur_segment++; pthread_mutex_unlock(&lock); zip_list[i] = wzip(segment_ptr, size); //index_cur_segment++; } //printf("ID %d getting out...\n", x); } int main(int argc, char *argv[]) { char c; int dummy; while((c = getopt(argc, argv, "s:")) != -1) { switch(c) { case 's': dummy = atoi(optarg); break; } } int n_segments = 0; int n_files = argc - optind; int n_threads = get_nprocs(); int fd[n_files]; file_ptr = malloc(n_files * sizeof(*file_ptr)); stat_buf = malloc(n_files * sizeof(*stat_buf)); pthread_t *workers = malloc(n_threads * sizeof(*workers)); if(!file_ptr || !stat_buf || !workers) { printf("Memory allocation error.\n"); return -1; } for (int i = 0; i < n_files; i++) { char *file_name = argv[optind]; fd[i] = open(file_name, O_RDONLY); fstat(fd[i], &stat_buf[i]); file_ptr[i] = mmap(NULL, stat_buf[i].st_size, PROT_READ, MAP_PRIVATE, fd[i], 0); int extra_segment = (segment_size % stat_buf[i].st_size) > 0 ? 1 : 0; n_segments += (stat_buf[i].st_size / segment_size) + extra_segment; } zip_list = malloc(n_segments * sizeof(*zip_list)); if(!zip_list) { printf("Memory allocation error.\n"); return -1; } for (int i = 0; i < n_threads; ++i) { pthread_create(&workers[i], NULL, segment_handler, NULL); } for (int i = 0; i < n_threads; ++i) { pthread_join(workers[i], NULL); } join(); for (int i = 0; i < n_files; i++) { munmap(file_ptr[i], stat_buf[i].st_size); } free(file_ptr); free(stat_buf); free(workers); free(zip_list); return 0; }
附图说明
- 图1:主线程中
n_segments的值为81 - 图2:子线程中
n_segments的值为0
原因分析与解决方案
核心问题
你在main函数中重新声明了一个局部变量n_segments:
int n_segments = 0;
这个局部变量会屏蔽全局作用域的n_segments。主线程中后续对n_segments的赋值操作,都是在操作这个局部变量,而非全局变量。而子线程的segment_handler函数访问的是全局的n_segments,它的初始值是0(全局变量未显式初始化时默认初始化为0),所以会出现值不一致的情况。
修复方法
删除main函数中局部的n_segments声明,直接使用全局变量即可:
// 去掉这一行:int n_segments = 0; n_segments = 0; // 改为直接对全局变量赋值初始化
额外注意事项
- 虽然全局变量在多线程间共享,但如果存在多个线程同时读写全局变量,必须保证操作的原子性(你已经用
pthread_mutex_t做了同步,这部分是正确的)。 - 局部变量和全局变量同名时,局部作用域的变量优先级更高,这种“变量遮蔽”问题很容易被忽略,编写代码时要注意避免。
内容的提问来源于stack exchange,提问作者EmTor
相关产品推荐
相关产品推荐

