MST

星途 面试题库

面试题:C语言共享内存销毁时的同步与异常处理

在Linux C语言开发中,当多个进程同时访问共享内存时,销毁共享内存可能会引发同步问题和异常情况。请阐述如何设计一个机制来确保共享内存安全地销毁,避免数据丢失或其他进程崩溃,并给出相应的代码示例及解释。
18.7万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试
  1. 设计机制
    • 使用信号量(Semaphore)来进行进程间同步。信号量可以控制对共享内存的访问,确保在销毁共享内存之前,没有其他进程正在使用它。
    • 维护一个引用计数。每个进程在使用共享内存时增加引用计数,结束使用时减少引用计数。当引用计数为0时,才可以安全地销毁共享内存。
  2. 代码示例
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <unistd.h>

#define SHM_SIZE 1024

// 定义共享内存结构
typedef struct {
    int ref_count;
    // 这里添加共享内存中实际的数据结构,例如:
    char data[SHM_SIZE];
} SharedMemory;

int main() {
    key_t key = ftok(".", 'a');
    if (key == -1) {
        perror("ftok");
        return 1;
    }

    int shmid = shmget(key, sizeof(SharedMemory), IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget");
        return 1;
    }

    SharedMemory *shmptr = (SharedMemory *)shmat(shmid, NULL, 0);
    if (shmptr == (void *)-1) {
        perror("shmat");
        return 1;
    }

    sem_t *sem = sem_open("/semaphore", 0);
    if (sem == SEM_FAILED) {
        perror("sem_open");
        return 1;
    }

    // 增加引用计数
    sem_wait(sem);
    shmptr->ref_count++;
    sem_post(sem);

    // 这里模拟进程对共享内存数据的使用
    printf("Process using shared memory. Data: %s\n", shmptr->data);

    // 减少引用计数
    sem_wait(sem);
    shmptr->ref_count--;
    if (shmptr->ref_count == 0) {
        // 只有当引用计数为0时,才销毁共享内存
        if (shmctl(shmid, IPC_RMID, NULL) == -1) {
            perror("shmctl IPC_RMID");
        }
    }
    sem_post(sem);

    if (shmdt(shmptr) == -1) {
        perror("shmdt");
        return 1;
    }

    sem_close(sem);
    return 0;
}
  1. 代码解释
    • ftok:生成一个唯一的键值,用于创建共享内存。
    • shmget:创建共享内存段,并返回共享内存标识符。
    • shmat:将共享内存段连接到当前进程的地址空间。
    • sem_open:打开一个已存在的信号量。信号量用于同步对共享内存引用计数的操作。
    • sem_waitsem_post:用于对信号量进行P(等待)和V(释放)操作,确保对引用计数的修改是原子操作,避免竞争条件。
    • shmptr->ref_count++shmptr->ref_count--:分别在进程开始使用和结束使用共享内存时增加和减少引用计数。
    • shmctl(shmid, IPC_RMID, NULL):当引用计数为0时,调用此函数销毁共享内存段。
    • shmdt:将共享内存段从当前进程的地址空间分离。
    • sem_close:关闭信号量。

通过这种机制,使用信号量保证引用计数操作的原子性,同时利用引用计数确保在所有进程都不再使用共享内存时才进行销毁,从而避免数据丢失和其他进程崩溃。