信号量(Semaphore)是操作系统中用于解决进程同步与互斥问题的一种经典机制

信号量(Semaphore)是操作系统中用于解决进程同步与互斥问题的一种经典机制,由荷兰计算机科学家艾兹赫尔·戴克斯特拉(Edsger W. Dijkstra)于1965年提出。它是一个整型变量,仅支持两种原子操作:

  • P操作(wait / down):将信号量值减1;若结果小于0,则调用进程阻塞并加入等待队列;
  • V操作(signal / up):将信号量值加1;若存在等待进程,则唤醒其中一个。

信号量分为两类:

  • 二元信号量(Binary Semaphore):取值仅为0或1,等价于互斥锁(Mutex),常用于实现临界区互斥;
  • 计数信号量(Counting Semaphore):取值为非负整数,用于控制对有限资源(如缓冲区、I/O设备)的访问数量。

信号量的核心价值在于其原子性保障(通常由硬件指令如test-and-set或compare-and-swap实现),避免竞态条件,是构建更高级同步原语(如管程、条件变量)的基础。

// 简化示意:不可直接用于实际并发环境(需底层原子支持)
typedef struct {
    int value;
    queue_t *wait_queue;  // 等待该信号量的进程队列
} semaphore_t;

void P(semaphore_t *s) {
    s->value--;
    if (s->value < 0) {
        block_current_process();   // 将当前进程加入s->wait_queue并阻塞
        add_to_wait_queue(s);
    }
}

void V(semaphore_t *s) {
    s->value++;
    if (s->value <= 0) {
        wakeup_one_from_queue(s);  // 唤醒一个等待进程
    }
}

P/V操作必须是原子的,是因为它们本质上是对共享变量(信号量值)的读-改-写(read-modify-write)操作,且其逻辑正确性严格依赖“不可分割执行”。若该操作被中断或与其他进程/线程的操作交错执行,将破坏信号量的语义,导致同步机制失效。

具体问题举例(以非原子P操作为例):

假设信号量 s.value = 1,两个进程 P₁ 和 P₂ 同时执行 P(s):

非原子P操作分解为三步(非原子执行):

  1. 读取 s.value → 得到 1
  2. 计算 s.value - 1 = 0
  3. 写回 s.value = 0

若执行顺序交错如下(时间轴从上到下):

时间P₁P₂
t₁读 s.value=1
t₂读 s.value=1
t₃计算得 0
t₄计算得 0
t₅写 s.value=0
t₆写 s.value=0

→ 最终 s.value = 0(正确值应为 -1,因两次P后应阻塞一个进程),但两个进程都通过了P操作,均进入临界区
违反互斥原则:本应只允许一个进程进入,却出现并发访问——典型竞态条件(race condition),可能导致数据不一致、状态错乱甚至系统崩溃。

类似地,非原子V操作可能造成:

  • 唤醒丢失(如多个V同时执行,仅一个生效,其余唤醒被覆盖);
  • 等待队列管理错误(如未正确检查是否有等待者就跳过唤醒)。

✅ 原子性保障方式:

  • 硬件支持:test-and-setcompare-and-swap (CAS)load-linked/store-conditional (LL/SC) 等指令;
  • 操作系统内核中常结合关中断(单核)或自旋锁+原子指令(多核)实现。
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bol5261

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值