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

Linux下C语言读写者共享内存异常求助:段错误+读取无输出

Linux C读写者共享内存程序错误排查与修复

问题描述

Linux环境下用C语言实现读写者模式共享内存程序,预期终端1(writer)输入内容后,终端2(reader)读取共享内存内容并打印。实际运行时writer触发段错误(segmentation fault),reader无法打印输入内容。

原Writer代码

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>

#define TRUE 1
#define FALSE 0

struct SHM_SIZE {
    char str[512];
    int flag, readcount;
};

sem_t *resourcemutex;
int shmid, EXIT;
void sigint_handler(int sig);
struct SHM_SIZE *ptr;

int main() {
    char str[512], ss[512];
    key_t key;
    key = 1053;
    EXIT=FALSE;

    if (signal(SIGINT, sigint_handler) == SIG_ERR) {
        perror("SIGQUIT");
        exit(1);
    }

    resourcemutex = sem_open("PRAK5-3RESC", O_CREAT, 0644, 1);
    if (resourcemutex == SEM_FAILED) {
        perror("unable to execute semaphore");
        sem_unlink("PRAK5-3RESC");
        exit(-1);
    }

    shmid = shmget(key, sizeof(struct SHM_SIZE), IPC_CREAT|0644);
    if (shmid < 0) {
        perror("shmget error...");
        exit(-1);
    }

    ptr = shmat(shmid, NULL, 0);
    
    int i = 0;

    while (EXIT == FALSE) {
        printf("Masukkan Kata/kalimat : ");
        scanf("%[^\n]", ss); getchar(); //The input to send to resourcemutex
        fflush(stdin);
        sem_wait(resourcemutex);
        strcpy(ptr->str, ss);
        ptr->flag = 1;
        sem_post(resourcemutex);
        i++;

        }
    sem_close(resourcemutex);

    return 0;
}

void sigint_handler(int sig) {
    EXIT = TRUE;  //to close resourcemutex
    
    sem_close(resourcemutex);
    sem_unlink("PRAK5-3RESC");
}

原Reader代码

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

#define TRUE 1
#define FALSE 0

struct SHM_SIZE {
    char str[512];
    int flag, readcount;
};

int EXIT;
int shmid;
sem_t *readermutex, *resourcemutex;
struct SHM_SIZE *ptr;

void sigint_handler(int sig);

int main() {
    int i, j;
    char ss[512], str[512];
    key_t key;
    EXIT=FALSE;

    if (signal(SIGINT, sigint_handler) == SIG_ERR) {
        perror("SIGQUIT");
        exit(1);
    }

    readermutex = sem_open("PRAK5-3READ", O_CREAT, 0644, 1);
    if (readermutex == SEM_FAILED) {
        perror("unable to create semaphore");
        sem_unlink("PRAK5-3READ");
        exit(-1);
    }

    resourcemutex = sem_open("PRAK5-3RESC", O_CREAT, 0644, 1);
    if (resourcemutex == SEM_FAILED) {
        perror("unable to create semaphore");
        sem_unlink("PRAK5-3READ");
        exit(-1);
    }

    shmid = shmget(key, sizeof(struct SHM_SIZE), IPC_CREAT | 0644);
    if (shmid < 0) {
        perror("failure in shmget");
        exit(-1);
    }

    ptr = shmat(shmid, NULL, 0);

    while (EXIT == FALSE) {
        sem_wait(resourcemutex);
        if (ptr->flag == 0) {
            usleep(1000);
            continue;
        } else {
            printf("Reading %s\n", ptr->str);
            ptr->flag = 0;
        }
        sem_post(resourcemutex);
    }
    return 0;
}

void sigint_handler(int sig) { //close the mutex
    EXIT = TRUE;

    sem_close(readermutex);
    sem_close(resourcemutex);
    sem_unlink("PRAK5-3READ");//close the mutex
    sem_unlink("PRAK5-3RESC");//close the mutex
    shmdt(ptr);
    shmctl(shmid, IPC_RMID, NULL);
    exit(0);
}

错误原因分析

  1. 共享内存未关联:Reader中key未初始化,导致与Writer使用不同的共享内存实例,数据无法互通。
  2. 未检查共享内存挂载结果:shmat失败时返回(void *)-1,直接访问ptr成员会触发段错误。
  3. 资源锁未正确释放:Reader中当ptr->flag == 0时直接跳过,未调用sem_post释放锁,导致Writer永久无法获取锁,程序逻辑阻塞。
  4. 输入处理不安全:scanf("%[^\n]", ss)无法处理空输入,且残留换行符会干扰后续输入,容易引发未定义行为。
  5. 全局变量未加volatile:信号处理函数修改EXIT后,主循环可能因编译器优化无法感知到值变化,导致无法正常退出。

修复后代码

修复后的Writer代码

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>

#define TRUE 1
#define FALSE 0

struct SHM_SIZE {
    char str[512];
    int flag, readcount;
};

sem_t *resourcemutex;
int shmid;
volatile int EXIT;
void sigint_handler(int sig);
struct SHM_SIZE *ptr;

int main() {
    char ss[512];
    key_t key = 1053;
    EXIT = FALSE;

    if (signal(SIGINT, sigint_handler) == SIG_ERR) {
        perror("SIGQUIT");
        exit(1);
    }

    resourcemutex = sem_open("PRAK5-3RESC", O_CREAT, 0644, 1);
    if (resourcemutex == SEM_FAILED) {
        perror("unable to execute semaphore");
        sem_unlink("PRAK5-3RESC");
        exit(-1);
    }

    shmid = shmget(key, sizeof(struct SHM_SIZE), IPC_CREAT|0644);
    if (shmid < 0) {
        perror("shmget error...");
        exit(-1);
    }

    ptr = shmat(shmid, NULL, 0);
    if (ptr == (void *)-1) {
        perror("shmat failed");
        exit(-1);
    }

    ptr->flag = 0;

    while (EXIT == FALSE) {
        printf("Masukkan Kata/kalimat : ");
        if (fgets(ss, sizeof(ss), stdin) == NULL) {
            break;
        }
        ss[strcspn(ss, "\n")] = '\0';

        sem_wait(resourcemutex);
        strncpy(ptr->str, ss, sizeof(ptr->str)-1);
        ptr->str[sizeof(ptr->str)-1] = '\0';
        ptr->flag = 1;
        sem_post(resourcemutex);
    }

    sem_close(resourcemutex);
    shmdt(ptr);
    return 0;
}

void sigint_handler(int sig) {
    EXIT = TRUE;
    
    sem_close(resourcemutex);
    shmdt(ptr);
    sem_unlink("PRAK5-3RESC");
}

修复后的Reader代码

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

#define TRUE 1
#define FALSE 0

struct SHM_SIZE {
    char str[512];
    int flag, readcount;
};

volatile int EXIT;
int shmid;
sem_t *readermutex, *resourcemutex;
struct SHM_SIZE *ptr;

void sigint_handler(int sig);

int main() {
    key_t key = 1053;
    EXIT = FALSE;

    if (signal(SIGINT, sigint_handler) == SIG_ERR) {
        perror("SIGQUIT");
        exit(1);
    }

    readermutex = sem_open("PRAK5-3READ", O_CREAT, 0644, 1);
    if (readermutex == SEM_FAILED) {
        perror("unable to create semaphore");
        sem_unlink("PRAK5-3READ");
        exit(-1);
    }

    resourcemutex = sem_open("PRAK5-3RESC", O_CREAT, 0644, 1);
    if (resourcemutex == SEM_FAILED) {
        perror("unable to create semaphore");
        sem_unlink("PRAK5-3RESC");
        exit(-1);
    }

    shmid = shmget(key, sizeof(struct SHM_SIZE), IPC_CREAT | 0644);
    if (shmid < 0) {
        perror("failure in shmget");
        exit(-1);
    }

    ptr = shmat(shmid, NULL, 0);
    if (ptr == (void *)-1) {
        perror("shmat failed");
        exit(-1);
    }

    while (EXIT == FALSE) {
        sem_wait(resourcemutex);
        if (ptr->flag == 1) {
            printf("Reading %s\n", ptr->str);
            ptr->flag = 0;
        }
        sem_post(resourcemutex);
        usleep(100000);
    }

    sem_close(readermutex);
    sem_close(resourcemutex);
    shmdt(ptr);
    return 0;
}

void sigint_handler(int sig) {
    EXIT = TRUE;

    sem_close(readermutex);
    sem_close(resourcemutex);
    sem_unlink("PRAK5-3READ");
    sem_unlink("PRAK5-3RESC");
    shmdt(ptr);
    shmctl(shmid, IPC_RMID, NULL);
    exit(0);
}

修复说明

  1. 统一共享内存key:Reader中初始化key = 1053,与Writer保持一致,确保使用同一块共享内存。
  2. 添加shmat返回值检查:避免访问无效内存地址引发段错误。
  3. 修复资源锁释放逻辑:Reader中无论是否读取到内容,都调用sem_post释放锁,防止死锁。
  4. 替换输入函数:用fgets替代scanf,更安全地处理输入,同时去掉读取到的换行符。
  5. 全局变量加volatile修饰:确保信号处理函数修改EXIT后,主循环能立即感知到变化。
  6. 初始化共享内存flag:Writer中初始化ptr->flag = 0,避免初始值不确定导致逻辑异常。

内容的提问来源于stack exchange,提问作者XI MIPA 1 MICHAEL ELBERT JUSTI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 13:44:58