当前位置: 首页 > news >正文

嵌入式Linux——“大扳手”与“小螺丝”:为什么不该用信号量(Semaphore)去模拟“完成量”(Completion)

问题理解

  • 既然有了信号量可以实现两个执行单元之间的同步,为什么Linux还要有一个完成量来做这件事情呢?
  • 答案是:它们在“设计意图”和“解决的特定问题”上完全不同。
  • 虽然你可以用一个初始化为 0 的信号量来模拟一个完成量,但这就像用一把大扳手去拧一颗小螺丝。能用,但很别扭,而且可能会出错
  • 完成量 (completion) 被发明出来,是为了解决一个信号量(semaphore)处理得不好(或者说“不优雅”)的特定问题

    “一个或多个任务,需要等待另一个任务执行完毕(或到达某个点)”。

核心区别:“意图” (Intent)

  • 这是最重要、最根本的区别,它决定了你该用哪个:
    • 信号量 (Semaphore):它的意图是“资源访问控制”。
      • 它像一个“令牌计数器”。down() 是为了获取一个令牌(资源使用权),up() 是为了归还一个令牌。
      • 你(程序员)看到 down() ,你的第一反应是:“哦,这里在锁定一个资源。”
    • 完成量 (Completion):它的意图是“事件信令”。
      • 它像一个“比赛的终点线”。wait_for_completion() 是为了等待一个事件发生。complete() 是为了宣布“事件已发生”。
      • 你看到 wait_for_completion(),你的第一反应是:“哦,这里在等待某个任务完成。”
  • 使用“意图”清晰的工具,能让代码变得容易阅读,不需要额外一层理解,极大降低了维护成本。

关键技术区别:专为“等待完成”而优化

  • 完成量在机制上就是为了“等待事件”而生的,它完美地解决了信号量在这里的两个痛点:
  1. 痛点一:致命的“先完成,后等待竞态 (Race Condition)

    • 这是信号量(用作信令时)最经典、最危险的BUG。
    • 场景:
      1. 你(任务A)创建了一个内核线程任务B),并想等待任务B初始化完毕后再继续
      2. 你决定用一个 sema(初始化为0)来同步。
    • 代码流程:
      1. 任务A:start_thread(B) -> down(&sema) (等待B完成)
      2. 任务B:do_init() -> up(&sem) (通知A已完成)
    • BUG 出现:如果任务B跑得非常快(比如在A调用 down() 之前,B就已经被调度、执行、并完成了 up() ):
      1. 任务A:start_thread(B)
      2. CPU 切换
      3. 任务B:do_init() -> up(&sema) (信号量 count 从 0 变成 1)
      4. CPU 切换
      5. 任务A:down(&sema) (发现 count 是 1,down() 成功,立即返回,根本不睡眠)
    • 结果:down(&sema)up(&sem) 之后执行,同步失败! sema 没能让 A 等待 B。(注:这是一个简化的例子,实际的竞态更复杂,但这种时序错乱是信号量用作信令时的核心风险)。
    • 完成量 (completion) 如何解决
      • complete() 会设置一个内部标志位(比如 done)。
      • wait_for_completion() 在决定是否睡眠前,会先检查这个 done 标志位。
      • 完美解决:
        1. 任务A:start_thread(B)
        2. CPU 切换
        3. 任务B:do_init() -> complete(&c) (将 c.done 标志设为 1)
        4. CPU 切换
        5. 任务A:wait_for_completion(&c)
        6. wait_… 内部检查:“哦?c.done 已经是 1 了?那说明我等的人已经跑完了。我根本不需要睡眠,直接返回。”
      • 完成量被设计为可以安全地处理“信号(complete)在等待(wait)之前发生” 的情况。

      (注:你可能会说“信号量count=1了,down()也会立刻返回啊?”。是的,但在信号量的设计意图里,这是“获取资源”,而不是“等待事件”。完成量把这个行为固化成了标准接口,更安全,更清晰。)

  2. 痛点二:如何“广播”?(Thundering Herd)

    • 信号量没有“广播”机制
    • 场景:你(写端)要删一个设备,有 5 个其他线程(读端)都在等待这个设备(比如 down() 了同一个 sema)。
    • up(&sema) 的问题:up() 只会唤醒一个等待的线程。你想唤醒所有人?你得自己写循环,for (i=0; i<5; i++) up(&sema);。这非常笨拙且容易出错。
    • complete() 的优势:完成量提供了两个版本的 complete
      • complete(c):只唤醒一个正在等待的线程。
      • complete_all(c):唤醒所有正在等待的线程。(专为“广播事件”(例如“设备已移除,你们都别等了”)而设计)
http://www.dtcms.com/a/590159.html

相关文章:

  • 哪个网站教做ppt网站优化主要工作有那些内容
  • 都江堰做网站糖果网站建设目的
  • 网站怎么建设以及维护网站维护能自己做吗
  • 湖南网站建设制作陈锦良厦门建设局
  • 做网站有哪些好处现在建设网站落后了
  • 汉中专业网站建设价格梨树县交通建设网站
  • 代码随想录 Q85.摆动序列
  • ESP32连接ThingsCloud上传设备数据(智慧小灯)
  • 网站设计公司圣辉友联一级a做爰片免费网站性恔
  • 【基于one-loop-per-thread的高并发服务器】--- Server模块
  • 免费网站推广网站在线怎么做网页啊
  • 泰安手机网站建设做校园文化的网站
  • 自助建站网站程序源码dw做网站弊端
  • 新城区网站建设做网站.服务器怎么买
  • 【教学类-98-01】20251109“兔子头像”(小班主题《小兔乖乖》)
  • 上海电子门户网站建设数据怎么用editplus做网站
  • iBiz开源:iBizPLM BOM插件来了
  • 8.游戏逆向-pxxx-获取GObject
  • 建立网站 数据分析网站怎么做动效
  • 什么软件做网站链接安宁市建设厅网站
  • 4.1.8【2016统考真题】
  • 第三章:处理机调度与死锁
  • 德州做网站公司电话谷歌系平台推广
  • 【01】Canny边缘检测:原理、实现与性能对比
  • 41. CMake
  • 11.string(上)
  • 【开题答辩全过程】以 基于SpringBoot的智慧教育系统的设计与实现为例,包含答辩的问题和答案
  • 360永久免费建网站网站建设及空间
  • 轻松阅读漫画的利器——Kotatsu漫画阅读器
  • 婚纱外贸网站怎么用PS做珠宝网站