面试题答案
一键面试信号量在进程同步与互斥中的基本原理
信号量(Semaphore)是一个整型变量,它通过一个计数器来控制对共享资源的访问。其基本原理如下:
- 互斥:当信号量的初始值设为1时,它可以用于实现互斥。此时信号量起到一个二元信号量(即0或1)的作用。进程在进入临界区(共享资源访问区域)前,先尝试获取信号量(将计数器减1),如果计数器值变为0,表示获取成功,可以进入临界区;若为负数(因为初始值为1,这里实际只能是 -1),表示已有其他进程占用,当前进程需等待。当进程离开临界区时,释放信号量(将计数器加1)。
- 同步:信号量初始值可设为其他正整数,用于表示可用资源的数量。进程需要使用资源时,尝试获取信号量(计数器减1),若计数器值大于等于0,表示有可用资源,可继续执行;若小于0,表示资源不足,进程进入等待队列。当进程使用完资源后,释放信号量(计数器加1),唤醒等待队列中的进程。
使用信号量解决生产者 - 消费者问题
假设共享缓冲区大小为 n
,我们需要使用三个信号量:
empty
:表示缓冲区中的空闲槽位,初始值为n
。full
:表示缓冲区中的已占用槽位,初始值为 0。mutex
:用于互斥访问缓冲区,初始值为 1。
以下是用伪代码示例:
生产者进程:
while (true) {
produce_item(); // 生产一个产品
wait(empty); // 等待缓冲区有空闲槽位
wait(mutex); // 进入临界区
add_item_to_buffer(); // 将产品放入缓冲区
signal(mutex); // 离开临界区
signal(full); // 通知缓冲区有新数据
}
消费者进程:
while (true) {
wait(full); // 等待缓冲区有数据
wait(mutex); // 进入临界区
remove_item_from_buffer(); // 从缓冲区取出产品
signal(mutex); // 离开临界区
signal(empty); // 通知缓冲区有空闲槽位
consume_item(); // 消费产品
}
在上述代码中,生产者先等待 empty
信号量(表示缓冲区有空闲空间),获取后进入临界区将产品放入缓冲区,然后释放 mutex
信号量(离开临界区)并发送 full
信号量(表示缓冲区有新数据)。消费者则先等待 full
信号量(表示缓冲区有数据),获取后进入临界区取出产品,然后释放 mutex
信号量(离开临界区)并发送 empty
信号量(表示缓冲区有空闲空间)。这样通过信号量的协调,实现了生产者和消费者之间的同步与对共享缓冲区的互斥访问。