Linux-Ubuntu环境下共享内存动态分配变量被其他进程修改不生效求助
问题根因定位
- 致命错误1:共享内存申请大小计算错误。你在
test.h中定义了typedef int* INT,也就是INT本质是int类型指针,不是int本身。START程序中shmget(shmKEY,4*sizeof(INT),IPC_CREAT | 0664)计算得到的是4个指针的大小(64位系统下为32字节),和你实际需要存储的4个int值的空间要求不匹配。 - 致命错误2:SECOND程序
shmget参数错误。你写的是shmget(shmKEY,0,IPC_CREAT | 0664),当第二个参数为0且携带IPC_CREAT标记时,如果共享内存创建失败/key不匹配,会直接生成一个大小为0的共享内存,后续操作该内存地址会触发段错误,程序直接崩溃退出,所以你看不到DEBUG0之后的输出,看起来就像操作被跳过了。 - 通用问题:所有系统调用都没有加返回值校验,无法定位具体失败步骤。
ftok、shmget、shmat、execl调用失败的场景你都没有做判断,出问题无法快速定位。 - 额外不规范点:
typedef int* INT这种写法非常容易混淆类型,极易出现sizeof计算错误的问题,非常不推荐。
修改方案
1. 修正test.h
取消容易混淆的指针类型定义:
#ifndef _TEST_H #define _TEST_H typedef int INT; #endif
2. 修正START程序代码
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/shm.h> #include <sys/ipc.h> #include "test.h" int main(){ key_t shmKEY; shmKEY= ftok(".",'a'); if(shmKEY == -1) { perror("ftok error"); return 1; } // 修正共享内存大小为4个int的总长度 int shmID = shmget(shmKEY, 4 * sizeof(int), IPC_CREAT | 0664); if(shmID == -1) { perror("shmget error"); return 1; } int* A; A = shmat(shmID, NULL, 0); if(A == (void*)-1) { perror("shmat error"); return 1; } A[0] = 1; A[1] = 2; A[2] = 3; A[3] = 4; for(int i = 0; i < 4; i++){ printf("[%d]", A[i]); } printf("\n"); pid_t pid; pid = fork(); if(pid < 0){ perror("fork error"); return 1; } else if(pid == 0){ execl("./SECOND", "./SECOND", NULL); perror("execl error"); exit(1); } if(pid > 0){ wait(NULL); for(int i = 0; i < 4; i++){ printf("[%d]", A[i]); } printf("\n"); } shmdt(A); shmctl(shmID, IPC_RMID, 0); return 0; }
3. 修正SECOND程序代码
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <sys/shm.h> #include <sys/ipc.h> int main(){ key_t shmKEY; shmKEY = ftok(".", 'a'); if(shmKEY == -1) { perror("ftok error"); return 1; } // 去掉IPC_CREAT标记,直接打开已创建的共享内存 int shmID = shmget(shmKEY, 4 * sizeof(int), 0664); if(shmID == -1) { perror("shmget error"); return 1; } int* A; A = shmat(shmID, NULL, 0); if(A == (void*)-1) { perror("shmat error"); return 1; } printf("DEBUG0\n"); A[0] = A[0] + 1; A[1] = A[1] + 1; A[2] = A[2] + 1; A[3] = A[3] + 1; for(int i = 0; i < 4; i++){ printf("[%d]", A[i]); } printf("\n"); printf("DEBUG1\n"); shmdt(A); return 0; }
4. 修正Makefile
注意Makefile中的缩进必须是Tab,不能是空格:
All: START SECOND START:main.o gcc main.o -o START SECOND:second.o gcc second.o -o SECOND second.o:second.c test.h gcc -c second.c main.o: main.c test.h gcc -c main.c clean: rm *.o START SECOND
验证步骤
- 如果之前有残留的错误共享内存,可执行
ipcs -m查看共享内存列表,用ipcrm -m 共享内存ID删除残留 - 执行
make clean清理旧编译产物,再执行make编译 - 运行
./START即可得到预期输出:
[1][2][3][4] DEBUG0 [2][3][4][5] DEBUG1 [2][3][4][5]
内容的提问来源于stack exchange,提问作者Neku Sakuraba
相关产品推荐
相关产品推荐

