在多进程环境中,信号量用于进程间的同步,以确保多个进程在访问共享资源时不会发生冲突。信号量机制通常由 P
操作(等待)和 V
操作(释放)组成,通过控制资源的访问权限来实现同步。
信号量是一种用于进程同步的整数,通常包含以下基本操作:
我们定义了一个信号量的结构体:
struct semaphore {
int value; // 信号量当前值
struct spinlock lock; // 用于保护信号量的锁
};
系统调用包括:
sys_sem_init
:初始化信号量并将其传回用户空间。sys_sem_signal
:执行 V 操作,释放信号量。sys_sem_wait
:执行 P 操作,等待信号量。uint64 sys_sem_init() {
uint64 addr;
int val;
struct semaphore *sem;
argaddr(0, &addr);
argint(1, &val);
sem = alloc_semaphore(); // 分配信号量内存
if (!sem) return -1;
sem_init(sem, val); // 初始化信号量
if (copyout(myproc()->pagetable, addr, (char*)&sem, sizeof(sem)) < 0)
return -1;
return 0;
}
uint64 sys_sem_signal() {
uint64 addr;
struct semaphore *sem;
argaddr(0, &addr);
if (copyin(myproc()->pagetable, (char*)&sem, addr, sizeof(sem)) < 0)
return -1;
sem_signal(sem); // 执行 V 操作
return 0;
}
uint64 sys_sem_wait() {
uint64 addr;
struct semaphore *sem;
argaddr(0, &addr);
if (copyin(myproc()->pagetable, (char*)&sem, addr, sizeof(sem)) < 0)
return -1;
sem_wait(sem); // 执行 P 操作
return 0;
}
我们为信号量分配内存,确保多个进程能共享相同的信号量地址,避免因信号量地址不一致导致进程无法互相唤醒的问题。
struct semaphore* alloc_semaphore() {
for (int i = 0; i < MAX_SEMAPHORES; i++) {
if (semaphores[i] == 0) {
semaphores[i] = (struct semaphore*)kalloc(); // kalloc 为内存分配函数
return semaphores[i];
}
}
return 0;
}
我们通过两个测试程序演示了信号量的实际应用: