MST
星途 面试题库

面试题:C语言Linux共享内存管理的同步问题

在多进程通过C语言操作Linux共享内存时,会遇到同步问题。请详细阐述如何使用信号量来解决共享内存的同步访问,并给出实现一个进程写共享内存、另一个进程读共享内存的代码示例,确保数据的一致性和完整性。
44.4万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

1. 信号量解决共享内存同步访问原理

在多进程环境下,信号量是一种计数器,用于控制对共享资源(如共享内存)的访问。

  • 初始化信号量:设置信号量的初始值,通常为1,表示共享资源可用。如果初始值为0,则表示共享资源已被占用。
  • 获取信号量:进程在访问共享内存前,先获取信号量。若信号量值大于0,则将其值减1,进程获得访问权;若信号量值为0,则进程阻塞,直到信号量值大于0。
  • 释放信号量:进程访问完共享内存后,释放信号量,即将信号量值加1,唤醒其他阻塞的进程。

2. 代码示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>

// 定义信号量操作函数
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 = SEM_UNDO;
    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 = SEM_UNDO;
    semop(semid, &sem_op, 1);
}

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

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

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

    // 挂载共享内存
    shared_memory = (char *)shmat(shmid, NULL, 0);
    if (shared_memory == (void *)-1) {
        perror("shmat");
        exit(1);
    }

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

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

    // 创建子进程
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(1);
    } else if (pid == 0) {
        // 子进程写共享内存
        semaphore_p(semid);
        printf("子进程正在写入共享内存...\n");
        sprintf(shared_memory, "Hello, shared memory!");
        semaphore_v(semid);
        // 分离共享内存
        if (shmdt(shared_memory) == -1) {
            perror("shmdt in child");
            exit(1);
        }
    } else {
        // 父进程读共享内存
        wait(NULL);
        semaphore_p(semid);
        printf("父进程正在读取共享内存: %s\n", shared_memory);
        semaphore_v(semid);
        // 分离共享内存
        if (shmdt(shared_memory) == -1) {
            perror("shmdt in parent");
            exit(1);
        }
        // 删除共享内存
        if (shmctl(shmid, IPC_RMID, NULL) == -1) {
            perror("shmctl");
            exit(1);
        }
        // 删除信号量
        if (semctl(semid, 0, IPC_RMID) == -1) {
            perror("semctl");
            exit(1);
        }
    }

    return 0;
}

3. 代码说明

  • 信号量操作函数semaphore_p 函数用于获取信号量(P操作),semaphore_v 函数用于释放信号量(V操作)。
  • 共享内存和信号量创建:使用 ftok 创建键值,通过 shmget 创建共享内存,semget 创建信号量,并使用 semctl 初始化信号量。
  • 进程操作:子进程先获取信号量,写入数据后释放信号量;父进程等待子进程完成写入,获取信号量后读取数据,最后释放信号量,并清理共享内存和信号量资源。