MST

星途 面试题库

面试题:C语言Linux进程共享资源在进程退出时的释放策略

在Linux系统中,使用C语言编写的进程涉及共享内存、信号量等共享资源。当进程退出时,为了避免资源泄露和保证系统稳定性,应该如何设计释放共享资源的策略?如果存在多个进程同时使用这些共享资源,又该如何协调资源释放以防止竞态条件?请从原理、数据结构设计以及代码实现等方面详细说明。
27.1万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

原理

  1. 共享内存释放原理:共享内存是多个进程可以共同访问的一块内存区域。当进程退出时,需要确保这块共享内存被正确释放,否则会导致内存泄漏。Linux提供了系统调用 shmctl 来控制共享内存,其中 IPC_RMID 命令用于标记共享内存段待删除。只有当所有使用该共享内存段的进程都脱离(shmdt)该段后,共享内存才会真正被删除。
  2. 信号量释放原理:信号量用于进程间同步和互斥访问共享资源。进程退出时,需要将占用的信号量释放,避免其他进程永远等待。semctl 系统调用中的 IPC_RMID 命令用于删除信号量集。

数据结构设计

  1. 共享内存:可以定义一个结构体来管理共享内存相关信息,例如:
typedef struct {
    key_t key;
    int shmid;
    void *shmaddr;
} SharedMemory;

key 是共享内存的键值,shmid 是共享内存标识符,shmaddr 是共享内存映射到进程地址空间的起始地址。 2. 信号量:定义一个结构体管理信号量相关信息,例如:

typedef struct {
    key_t key;
    int semid;
} Semaphore;

key 是信号量的键值,semid 是信号量标识符。

代码实现

  1. 共享内存释放
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>

#define SHM_SIZE 1024

int main() {
    SharedMemory shm;
    shm.key = ftok(".", 'a');
    if (shm.key == -1) {
        perror("ftok");
        return 1;
    }
    shm.shmid = shmget(shm.key, SHM_SIZE, IPC_CREAT | 0666);
    if (shm.shmid == -1) {
        perror("shmget");
        return 1;
    }
    shm.shmaddr = shmat(shm.shmid, NULL, 0);
    if (shm.shmaddr == (void *)-1) {
        perror("shmat");
        return 1;
    }
    // 使用共享内存
    //...
    // 进程退出前释放共享内存
    if (shmdt(shm.shmaddr) == -1) {
        perror("shmdt");
        return 1;
    }
    if (shmctl(shm.shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl IPC_RMID");
        return 1;
    }
    return 0;
}
  1. 信号量释放
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

int main() {
    Semaphore sem;
    sem.key = ftok(".", 'b');
    if (sem.key == -1) {
        perror("ftok");
        return 1;
    }
    sem.semid = semget(sem.key, 1, IPC_CREAT | 0666);
    if (sem.semid == -1) {
        perror("semget");
        return 1;
    }
    union semun arg;
    arg.val = 1;
    if (semctl(sem.semid, 0, SETVAL, arg) == -1) {
        perror("semctl SETVAL");
        return 1;
    }
    // 使用信号量
    //...
    // 进程退出前释放信号量
    if (semctl(sem.semid, 0, IPC_RMID) == -1) {
        perror("semctl IPC_RMID");
        return 1;
    }
    return 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>

#define SHM_SIZE 1024

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

void sem_down(int semid, int num) {
    struct sembuf sb;
    sb.sem_num = num;
    sb.sem_op = -1;
    sb.sem_flg = SEM_UNDO;
    if (semop(semid, &sb, 1) == -1) {
        perror("sem_down");
        exit(1);
    }
}

void sem_up(int semid, int num) {
    struct sembuf sb;
    sb.sem_num = num;
    sb.sem_op = 1;
    sb.sem_flg = SEM_UNDO;
    if (semop(semid, &sb, 1) == -1) {
        perror("sem_up");
        exit(1);
    }
}

int main() {
    SharedMemory shm;
    Semaphore sem;
    shm.key = ftok(".", 'a');
    if (shm.key == -1) {
        perror("ftok for shm");
        return 1;
    }
    shm.shmid = shmget(shm.key, SHM_SIZE, IPC_CREAT | 0666);
    if (shm.shmid == -1) {
        perror("shmget");
        return 1;
    }
    shm.shmaddr = shmat(shm.shmid, NULL, 0);
    if (shm.shmaddr == (void *)-1) {
        perror("shmat");
        return 1;
    }

    sem.key = ftok(".", 'b');
    if (sem.key == -1) {
        perror("ftok for sem");
        return 1;
    }
    sem.semid = semget(sem.key, 1, IPC_CREAT | 0666);
    if (sem.semid == -1) {
        perror("semget");
        return 1;
    }
    union semun arg;
    arg.val = 1;
    if (semctl(sem.semid, 0, SETVAL, arg) == -1) {
        perror("semctl SETVAL");
        return 1;
    }

    // 使用共享内存和信号量
    //...

    // 进程退出前协调释放共享内存
    sem_down(sem.semid, 0);
    if (shmdt(shm.shmaddr) == -1) {
        perror("shmdt");
        return 1;
    }
    if (shmctl(shm.shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl IPC_RMID");
        return 1;
    }
    sem_up(sem.semid, 0);

    // 释放信号量
    if (semctl(sem.semid, 0, IPC_RMID) == -1) {
        perror("semctl IPC_RMID");
        return 1;
    }
    return 0;
}

通过上述代码,在释放共享资源(共享内存和信号量)时,先获取协调信号量,完成释放后再释放该信号量,从而防止竞态条件。