面试题答案
一键面试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
初始化信号量。 - 进程操作:子进程先获取信号量,写入数据后释放信号量;父进程等待子进程完成写入,获取信号量后读取数据,最后释放信号量,并清理共享内存和信号量资源。