MST

星途 面试题库

面试题:C语言Linux共享内存的读写同步

在Linux系统中,用C语言创建两个进程,通过共享内存进行数据传递。一个进程往共享内存写入字符串,另一个进程从共享内存读取并打印。请考虑如何使用信号量机制来保证读写操作的同步,写出完整代码及关键步骤说明。
43.0万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>

#define SHM_SIZE 1024

// 信号量操作函数
union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};

void semaphore_p(int semid) {
    struct sembuf sem_op;
    sem_op.sem_num = 0;
    sem_op.sem_op = -1;
    sem_op.sem_flg = 0;
    semop(semid, &sem_op, 1);
}

void semaphore_v(int semid) {
    struct sembuf sem_op;
    sem_op.sem_num = 0;
    sem_op.sem_op = 1;
    sem_op.sem_flg = 0;
    semop(semid, &sem_op, 1);
}

int main() {
    key_t key;
    int shmid, semid;
    char *shmaddr;

    // 创建共享内存的键值
    if ((key = ftok(".", 'a')) == -1) {
        perror("ftok");
        exit(1);
    }

    // 创建共享内存
    if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) == -1) {
        perror("shmget");
        exit(1);
    }

    // 共享内存映射到进程地址空间
    if ((shmaddr = (char *)shmat(shmid, 0, 0)) == (void *)-1) {
        perror("shmat");
        exit(1);
    }

    // 创建信号量
    if ((semid = semget(key, 1, IPC_CREAT | 0666)) == -1) {
        perror("semget");
        exit(1);
    }

    // 初始化信号量值为0
    union semun sem_union;
    sem_union.val = 0;
    if (semctl(semid, 0, SETVAL, sem_union) == -1) {
        perror("semctl");
        exit(1);
    }

    // 创建子进程
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(1);
    } else if (pid == 0) { // 子进程,负责写
        char message[] = "Hello, shared memory!";
        strcpy(shmaddr, message);
        printf("子进程写入: %s\n", message);
        // 写入完成,释放信号量
        semaphore_v(semid);
    } else { // 父进程,负责读
        // 等待信号量
        semaphore_p(semid);
        printf("父进程读取: %s\n", shmaddr);
        // 分离共享内存
        if (shmdt(shmaddr) == -1) {
            perror("shmdt");
            exit(1);
        }
        // 删除共享内存
        if (shmctl(shmid, IPC_RMID, 0) == -1) {
            perror("shmctl");
            exit(1);
        }
        // 删除信号量
        if (semctl(semid, 0, IPC_RMID, 0) == -1) {
            perror("semctl");
            exit(1);
        }
    }

    return 0;
}

关键步骤说明:

  1. 生成共享内存键值:使用ftok函数生成一个唯一的键值,用于创建共享内存和信号量。
  2. 创建共享内存:调用shmget函数创建共享内存段,并获取其标识符shmid
  3. 映射共享内存:使用shmat函数将共享内存段映射到进程的地址空间,返回共享内存的地址shmaddr
  4. 创建信号量:通过semget函数创建一个信号量,用于同步读写操作,获取信号量标识符semid
  5. 初始化信号量:利用semctl函数将信号量初始值设为0。
  6. 创建子进程:使用fork函数创建子进程,子进程负责写入共享内存,父进程负责读取共享内存。
  7. 子进程写操作:子进程将字符串写入共享内存后,调用semaphore_v函数释放信号量,表示数据已写入。
  8. 父进程读操作:父进程调用semaphore_p函数等待信号量,当信号量可用时,从共享内存读取数据并打印,之后分离并删除共享内存以及信号量。