【问题标题】:Behavior of sched_yieldsched_yield 的行为
【发布时间】:2011-09-15 11:18:36
【问题描述】:

我对@9​​87654321@ 函数没有几个问题,因为我发现它没有按照我的代码中的预期运行。很多时候,当我尝试通过调用sched_yield 来让出它时,即使存在其他线程,我也会看到同一个线程一次又一次地运行。

另外,如果我有多核,sched_yield 是否会为在所有内核或仅一个内核上运行的线程产生收益。例如,我在核心 1 上运行线程 1、2 和 3,在核心 2 上运行线程 4、5 和 6,如果从线程 2 调用 sched_yield,它将仅被线程 1 和 3 或 1 替换, 3、4、5、6都可以吗?我问这个是因为在 .Net Thread.Yield 中只让步于在同一核心/处理器上运行的线程。

【问题讨论】:

  • 你打算如何运作? TBH,我真的不明白为什么这个调用有用,无论是在 POSIX/***X、Windows 还是任何抢占式多任务程序上。如果你让出你的线程,你不能保证操作系统不会立即再次加载它,如果其他线程当时还没有准备好,也许在同一个核心上。如果 .NET 版本具有处理器亲和性,(是的,我用 Google 搜索过它似乎有),那就更奇怪了——我猜它可能会提高纤维的性能?
  • @MartinJames 当您拥有比核心更多的可运行进程/线程并且您想给其他线程/进程一个取得进展的机会时(例如,一个线程刚刚给另一个线程一些东西),这是一个有用的调用做和第一个线程进入睡眠等待完成的成本超过(第二个线程做“某事”+第一个线程检查它是否已经完成)的成本。

标签: multithreading linux-kernel yield scheduler


【解决方案1】:

http://www.kernel.org/doc/man-pages/online/pages/man2/sched_yield.2.html

sched_yield() 导致调用线程放弃 CPU。线程是 移动到队列的末尾以获取其静态优先级,并且一个新线程到达 运行。

如果调用线程是最高优先级列表中唯一的线程 时间,它会在调用 sched_yield() 后继续运行。

sched_yield 不是 .Net 调用,线程/进程模型与此不同。 Windows/.NET 的调度器与 Linux 的调度器不同。 Linux 甚至有几种可能的调度器。

所以,您对 sched_yield 的期望是错误的。

如果您想控制线程如何运行,您可以将每个线程绑定到 CPU。然后,线程将仅在绑定的 CPU 上运行。如果您将有多个线程绑定到同一个 CPU,则使用 sched_yield MAY 切换到绑定到当前 CPU 并准备运行的另一个线程。

如果每个线程都想做大量 CPU 密集型工作,那么每个 CPU 使用多个线程可能是个坏主意。

如果您想完全控制线程的运行方式,您可以使用实时线程。 http://www.linuxjournal.com/magazine/real-time-linux-kernel-scheduler - SCHED_FIFO 和 SCHED_RR RT 策略。

【讨论】:

    【解决方案2】:

    为什么要放弃 CPU?嗯……

    我正在修复客户端代码中的错误。基本上,它们有一个共享结构来保存信息:

    1. 代管中有多少硬币 - 归还它们
    2. 托管中有多少账单 - 退回它们

    以上代码在进程 A 中。其余代码在进程 B 中。进程 B 向进程 A 发送消息以计算并返回托管中的钱(这是一台自动售货机)。不用深入了解为什么代码是这样写的历史,原来的代码顺序是:

    (过程 B) 向进程 A 发送消息 RETURN_ESCROWED_BILLS 向进程 A 发送消息 RETURN_ESCROWED COINS 将通用结构清零

    这将被执行为:

    (过程 B): 发送消息; 将结构清零;

    (稍后.. 过程 A): 获取消息; 公共结构中的所有字段都是0; 无事可做;

    哎呀...钱仍在托管中,但过程 A 代码已丢失该知识。真正需要的是(除了代码的大规模重组):

    (过程 B): 发送消息; 让出 CPU;

    (过程 A): 确定托管资金和回报; 让出 CPU; (可以直接到时间片的末尾,不需要特殊方法)

    (过程 B): 将公共结构清零;

    任何时候您都有 IPC 消息,并且发送/接收消息的进程紧密耦合最好的方法是进行两次握手。但是,在某些情况下(通常是由于设计不佳或不存在),您必须紧密耦合实际上应该松耦合的进程。 通常 CPU 的产量是一个 hack,因为你别无选择。添加多核 CPU 是一个痛苦的根源,尤其是在从单核移植到多核时。

    【讨论】:

    • 这个答案是错误的。 sched_yield() 不适用于进程间通信,调用它也不会确保另一个线程实际运行。正如 osgx 所描述的,这个想法是为了帮助操作系统有效地调度。
    • 是的,sched_yield() 并不明确用于进程间通信,但是:发送线程需要以可预测的方式放弃 CPU,以便接收线程真正有机会获得 CPU。此外,两个进程处于相同的优先级,并且接收线程正在阻塞,等待消息。否则,在发送任务失去 CPU 和接收任务获得 CPU 之间存在竞争。这种方法是可预测的(Ubunto 8)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多