基于Peterson算法实现双线程共享内存临界区互斥时遇段错误求助
修复Peterson算法线程互斥实现的段错误与同步问题
问题分析
1. 段错误根源
你在创建线程时直接将整数0、1强转为void*传递:
pthread_create(&t1, NULL, switching, (void*)0); pthread_create(&t2, NULL, switching, (void*)1);
但线程函数中尝试解引用这个指针:
int procNum = *(int*)process;
这相当于访问内存地址0或1的非法区域,直接触发段错误。
2. 同步逻辑的隐藏问题
全局变量flag和turn未加volatile修饰,编译器可能会将这些变量缓存到寄存器,导致线程无法感知其他线程的修改,破坏Peterson算法的互斥正确性。
修复步骤
1. 修正线程参数传递
直接将void*类型的参数强转为整数,无需解引用:
int procNum = (int)process;
2. 阻止编译器优化同步变量
给flag和turn添加volatile修饰,确保每次访问都从内存读取:
volatile int flag[2]; volatile int turn;
3. 修正输出格式(可选)
原代码中printf的换行符错误,修正为\n保证输出整洁。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <pthread.h> // volatile修饰同步变量,避免编译器优化 volatile int flag[2]; volatile int turn; int* sharedMemory; void lock_process(int procNum) { flag[procNum] = 1; turn = 1 - procNum; // Peterson算法等待条件:对方也想进入且轮到对方 while (flag[1 - procNum] == 1 && turn == 1 - procNum); } void unlock_process(int procNum) { flag[procNum] = 0; } void* switching(void* process) { int i = 0; // 直接将void*转为线程编号,无需解引用 int procNum = (int)process; printf("Thread Entered: %d\n", procNum); lock_process(procNum); // 临界区:安全操作共享内存 for (i = 0; i < 1000; i++) { (*sharedMemory)++; } unlock_process(procNum); return NULL; } int main() { pthread_t t1, t2; flag[0] = 0; flag[1] = 0; turn = 0; sharedMemory = (int*)malloc(sizeof(int)); if (sharedMemory == NULL) { perror("malloc error"); exit(1); } *sharedMemory = 0; // 传递整数作为线程参数 pthread_create(&t1, NULL, switching, (void*)0); pthread_create(&t2, NULL, switching, (void*)1); pthread_join(t1, NULL); pthread_join(t2, NULL); // 打印最终结果验证互斥效果 printf("Final sharedMemory value: %d\n", *sharedMemory); free(sharedMemory); return 0; }
编译运行
编译时必须链接pthread库:
gcc peterson.c -o peterson -pthread ./peterson
正常运行后会输出Final sharedMemory value: 2000,说明互斥逻辑生效。
内容的提问来源于stack exchange,提问作者pkh
相关产品推荐
相关产品推荐

