面试题答案
一键面试信号量实现进程间同步与互斥原理
信号量(Semaphore)是一个整型变量,通过一个计数器来控制对共享资源的访问。当计数器的值大于0时,表示有可用资源,进程可以获取信号量(计数器减1)来访问资源;当计数器的值为0时,表示资源已被占用,进程需要等待信号量释放(计数器加1)。
C++ 代码示例
在C++中,可以使用POSIX信号量来实现进程间同步与互斥。以下是一个简单的示例代码,展示如何初始化、获取和释放信号量:
#include <iostream>
#include <semaphore.h>
#include <unistd.h>
#include <sys/wait.h>
const int sharedResource = 0; // 共享资源
int main() {
sem_t* semaphore;
// 初始化信号量,值为1表示初始时有一个可用资源(用于互斥)
semaphore = sem_open("/my_semaphore", O_CREAT, 0666, 1);
if (semaphore == SEM_FAILED) {
std::cerr << "Failed to create semaphore" << std::endl;
return 1;
}
pid_t pid = fork();
if (pid == -1) {
std::cerr << "Fork failed" << std::endl;
sem_close(semaphore);
sem_unlink("/my_semaphore");
return 1;
} else if (pid == 0) { // 子进程
// 获取信号量
if (sem_wait(semaphore) == 0) {
std::cout << "Child process entered critical section" << std::endl;
// 访问共享资源
std::cout << "Child process accessing shared resource: " << sharedResource << std::endl;
// 释放信号量
sem_post(semaphore);
std::cout << "Child process left critical section" << std::endl;
} else {
std::cerr << "Child process failed to acquire semaphore" << std::endl;
}
} else { // 父进程
// 获取信号量
if (sem_wait(semaphore) == 0) {
std::cout << "Parent process entered critical section" << std::endl;
// 访问共享资源
std::cout << "Parent process accessing shared resource: " << sharedResource << std::endl;
// 释放信号量
sem_post(semaphore);
std::cout << "Parent process left critical section" << std::endl;
wait(nullptr); // 等待子进程结束
} else {
std::cerr << "Parent process failed to acquire semaphore" << std::endl;
}
}
// 关闭并删除信号量
sem_close(semaphore);
sem_unlink("/my_semaphore");
return 0;
}
信号量值的设置
- 互斥场景:
- 信号量初始值设为1。这意味着同一时间只有一个进程可以获取信号量,进入临界区访问共享资源,从而实现互斥。在上述代码中,
sem_open("/my_semaphore", O_CREAT, 0666, 1);
将信号量初始值设为1。
- 信号量初始值设为1。这意味着同一时间只有一个进程可以获取信号量,进入临界区访问共享资源,从而实现互斥。在上述代码中,
- 同步场景(如生产者 - 消费者模型):
- 资源可用信号量:如果有N个初始可用资源,信号量初始值设为N。例如,在生产者 - 消费者模型中,如果缓冲区初始有5个空位,那么表示缓冲区空位的信号量初始值设为5。消费者进程在从缓冲区取数据前获取该信号量(信号量值减1),生产者进程向缓冲区写数据后释放该信号量(信号量值加1)。
- 资源占用信号量:如果要表示缓冲区已占用的数量,初始值设为0。生产者进程向缓冲区写数据前获取该信号量(因为初始无数据,需等待消费者取数据后才有空位),消费者进程从缓冲区取数据后释放该信号量。