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

共享内存元素操作触发段错误,求排查与解决方法

共享内存操作触发段错误的排查与修复

问题描述

编写了一段向共享内存插入结构体的C语言代码,调试发现对共享内存元素操作时触发段错误,甚至shared_pid_atom->dimensione = 0;这类简单赋值都失败。代码如下:

static shared_pid_data *shared_pid_atom;

static int shmidA;
static int semidA;

void atomSharedPidInit(){
    key_t key = ftok("shmfileA",65);
    printf("atomSharedPidInit - key = ftok\n");
    shmidA = shmget(key, sizeof(shared_pid_data), 0666|IPC_CREAT);
    printf("atomSharedPidInit - shmget\n");
    shared_pid_atom = (shared_pid_data*) shmat(shmidA, (void*)0, 0);
    printf("atomSharedPidInit - shmat\n");
    key_t sem_key = ftok("semfileA", 75);
    printf("atomSharedPidInit - sem_key = ftok\n");
    semidA = semget(sem_key, 1, 0666 | IPC_CREAT);
    printf("atomSharedPidInit - semget\n");
    semctl(semidA, 0, SETVAL, 1);
    printf("atomSharedPidInit - semctl\n");
}

void lockA() {
    struct sembuf sba = {(unsigned short) 0, -1, 0};
    semop(semidA, &sba, 1);
}

void unlockA() {
    struct sembuf sba = {(unsigned short) 0, 1, 0};
    semop(semidA, &sba, 1);
}

void atomSharedPidWrite(pid_t pid) {
    lockA();
    printf("atomSharedPidWrite - lock\n");
    int dim = shared_pid_atom->dimensione;
    printf("atomSharedPidWrite - int dim\n");
    if (dim < 1000) {
        printf("atomSharedPidWrite - if\n");
        shared_pid_atom->atomi_pid[shared_pid_atom->dimensione] = pid;
        shared_pid_atom->dimensione++;
        printf("pid : %d  dimensione : %d ",shared_pid_atom->atomi_pid[shared_pid_atom->dimensione-1],shared_pid_atom->dimensione);
    } else {
        fprintf(stderr, "Shared memory is full\n");
    }
    unlockA();
}

int main (){
    atomSharedPidInit();
    printf("simulazione - atomSharedPidInit\n");
    alarm((unsigned int)sim_duration);
    printf("simulazione - alarm\n");
    print_statistics();

    for (int i = 0; i < n_atomi_init; i++) {
        atomoPID = fork();
        if (atomoPID == 0) {
            printf("Atomo - fork\n");
            srand((unsigned int)(time(NULL) + getpid()));
            printf("Atomo - srand\n");
            atomSharedPidWrite(getpid());
            printf("Atomo - atomSharedPidWrite(getpid())\n");
            
            int numero_atomico = rand() % max_num_atomico + min_num_atomico;
            printf("%d %d %d ", numero_atomico, max_num_atomico, min_num_atomico);
            char num_atomico_str[10];
            sprintf(num_atomico_str, "%d", numero_atomico);
            execl("./atomo", "./atomo", num_atomico_str, NULL);
            exit(0);
        } else if (atomoPID < -1) {
            kill(getpid(), SIGINT);
            exit(EXIT_FAILURE);
        }
    }
}

运行输出:

atomSharedPidInit - key = ftok
atomSharedPidInit - shmget
atomSharedPidInit - shmat
atomSharedPidInit - sem_key = ftok
atomSharedPidInit - semget
atomSharedPidInit - semctl
simulazione - atomSharedPidInit
simulazione - alarm
Current state:
Total energy: 0
Total energy consumed: 0
Total energy available: 0
Total atomi attivi: 0
Total scissions: 0
Total activations: 0
Total scorie: 0
+---------------------------------------------------+
Atomo - fork
Atomo - srand
atomSharedPidWrite - lock
Atomo - fork
Atomo - srand
Atomo - fork
Atomo - srand
Atomo - fork
Atomo - fork
Atomo - srand
Atomo - srand
atomSharedPidWrite - lock
atomSharedPidWrite - lock
atomSharedPidWrite - lock
atomSharedPidWrite - lock
make: *** [Makefile:38: run] Errore di segmentazione (creato dump del core)

问题分析

从输出看,子进程执行到atomSharedPidWrite - lock后触发段错误,核心原因集中在以下几点:

  • 共享内存挂载失败未检查:shmat返回(void*)-1表示挂载失败,但代码未做校验,导致shared_pid_atom是无效指针,后续访问直接触发段错误。
  • ftok依赖的文件不存在:ftok需要依赖的文件(shmfileA、semfileA)必须存在,若文件不存在,ftok返回-1,后续shmget和semget会失败,导致共享内存/信号量ID无效。
  • 共享内存结构体初始化缺失:首次创建共享内存时,内存内容是随机值,dimensione可能是极大值,导致数组越界访问。
  • 信号量操作未做错误检查:semop、semctl可能执行失败,导致锁机制失效,多进程同时操作共享内存引发竞态,进而触发段错误。

修复方案

1. 检查所有IPC调用的返回值

在每个IPC函数调用后添加错误检查,确保操作成功:

// 需提前定义semun联合体(部分系统需手动定义)
union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};

void atomSharedPidInit(){
    // 确保ftok依赖文件存在
    int fd = open("shmfileA", O_CREAT | O_RDWR, 0666);
    if (fd == -1) { perror("open shmfileA failed"); exit(EXIT_FAILURE); }
    close(fd);

    fd = open("semfileA", O_CREAT | O_RDWR, 0666);
    if (fd == -1) { perror("open semfileA failed"); exit(EXIT_FAILURE); }
    close(fd);

    key_t key = ftok("shmfileA",65);
    if (key == -1) { perror("ftok shmfileA failed"); exit(EXIT_FAILURE); }
    printf("atomSharedPidInit - key = ftok\n");

    shmidA = shmget(key, sizeof(shared_pid_data), 0666|IPC_CREAT);
    if (shmidA == -1) { perror("shmget failed"); exit(EXIT_FAILURE); }
    printf("atomSharedPidInit - shmget\n");

    shared_pid_atom = (shared_pid_data*) shmat(shmidA, (void*)0, 0);
    if (shared_pid_atom == (void*)-1) { perror("shmat failed"); exit(EXIT_FAILURE); }
    printf("atomSharedPidInit - shmat\n");

    // 首次创建共享内存时初始化结构体
    struct shmid_ds shm_info;
    if (shmctl(shmidA, IPC_STAT, &shm_info) == 0 && shm_info.shm_nattch == 1) {
        shared_pid_atom->dimensione = 0;
        memset(shared_pid_atom->atomi_pid, 0, sizeof(shared_pid_atom->atomi_pid));
    }

    key_t sem_key = ftok("semfileA", 75);
    if (sem_key == -1) { perror("ftok semfileA failed"); exit(EXIT_FAILURE); }
    printf("atomSharedPidInit - sem_key = ftok\n");

    semidA = semget(sem_key, 1, 0666 | IPC_CREAT);
    if (semidA == -1) { perror("semget failed"); exit(EXIT_FAILURE); }
    printf("atomSharedPidInit - semget\n");

    union semun sem_union;
    sem_union.val = 1;
    if (semctl(semidA, 0, SETVAL, sem_union) == -1) { perror("semctl SETVAL failed"); exit(EXIT_FAILURE); }
    printf("atomSharedPidInit - semctl\n");
}

2. 修复信号量操作的错误检查

修改lockA和unlockA函数,添加错误检查:

void lockA() {
    struct sembuf sba = {(unsigned short) 0, -1, 0};
    if (semop(semidA, &sba, 1) == -1) { perror("semop lock failed"); exit(EXIT_FAILURE); }
}

void unlockA() {
    struct sembuf sba = {(unsigned short) 0, 1, 0};
    if (semop(semidA, &sba, 1) == -1) { perror("semop unlock failed"); exit(EXIT_FAILURE); }
}

3. 确认shared_pid_data结构体定义正确

确保结构体中的atomi_pid数组大小至少为1000:

#define MAX_ATOMI 1000

typedef struct {
    int dimensione;
    pid_t atomi_pid[MAX_ATOMI];
} shared_pid_data;

验证修复效果

添加上述检查和初始化后,程序应能正常操作共享内存,不会触发段错误。若仍有问题,可通过gdb调试core文件,定位段错误具体位置进一步排查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 10:35:00