在阅读操作系统三个简单的片段时,我发现了以下句子:
"要在单个处理器上正常工作,它需要抢占式调度程序(即通过计时器中断线程的调度程序, 为了不时运行不同的线程。没有 抢占,自旋锁在单个CPU上没有多大意义,因为 在CPU上旋转的线程永远不会放弃它。"
为什么即使单个CPU支持多线程,在单个CPU上旋转的线程也永远不会放弃它?是不是因为在这种情况下,自旋锁只会浪费太多的CPU资源? CPU内核的数量如何影响不同锁的性能,如互斥锁和自旋锁?
答案 0 :(得分:3)
在单CPU,单核CPU上,您仍然可以thread multi-tasking(多线程),但需要注意的是,由于缺少多个线程,通常只能执行一个线程执行单位。如果没有多个执行单元(硬件多线程),硬件依赖于内核定义的“software multi-threading”策略 - 低级操作系统软件来确定执行什么以及何时执行。
Preemption是一种策略,涉及更加活跃的牧羊(可以这么说)沿着单一路径执行这些多个执行流,这些流通常部分地通过基于使用定时器的中断来实现。与抢占相反 - cooperative scheduling - 采用更自由放任的方法,将其留给活动线程来表示它是完整的。
因此,协作调度方案允许一个线程进程的线程保持唯一的计算资源(在这种情况下)更长时间:
但是如果这样的计划中的活跃线程试图永远保持活跃呢?这就是本质上发生的事情。
自旋锁是一种主动等待锁定请求的资源。线程将只是坐在那里等待其他线程锁定它想要放弃它的资源。由于文本表明硬件情况一次只允许一个活动线程,如果请求的资源被锁定,这意味着它被非活动线程锁定。
没有先发制人,由线程决定何时停止执行。因此,当活动线程旋转锁定时,它将永远位于那里 - 即所谓的挂起。要停止此操作,用户可能会被迫在物理上关闭系统以清除缓存/动态内存。
使用抢占式调度线程实现为time slices。在线程中完成进一步工作之前,访问特定资源是必需的spinlock - 忙碌的等待 - 是有意义的。
通过抢占,内核将在指定的时间后自动force context switch,因此即使使用单个CPU也不会挂起。最终,具有资源lock的线程将获得一些时间并释放其资源。当自旋锁线程获得下一个预定时间时,它将能够锁定资源并继续。
总的来说,这意味着更少的挂起。
然而,对于抢占式调度,自旋锁仍然会遇到更复杂的问题,例如死锁......当两个线程都被自旋锁定而同时保持彼此的资源时:
但是,这种情况通常可以通过资源锁定请求的内核安全措施来避免。
在一个完美的世界中,通过细致的线程设计进行协同调度可能会使关键进程的执行速度加快。因此,在Mac OS和Windows 3.x等精简旧操作系统中,这是一种常见的方法。然而,随着计算需求的增加,避免协同调度的缺点变得更加困难,因此几乎所有现代操作系统内核都使用抢先式调度程序。