为什么自旋锁在单个 CPU 上没有意义?

Why do spin locks make no sense on a single CPU?

在阅读操作系统三篇时,我发现了以下句子:

"To work correctly on a single processor, it requires a preemptive scheduler (i.e., one that will interrupt a thread via a timer, in order to run a different thread, from time to time). Without preemption, spin locks don’t make much sense on a single CPU, as a thread spinning on a CPU will never relinquish it."

为什么单CPU支持多线程,单CPU上的线程永远不会放弃?是因为在这种情况下自旋锁只是浪费了太多 CPU 资源吗? CPU 内核的数量如何影响互斥锁和自旋锁等不同锁的性能?

在单个 CPU、single-core CPU 上,您仍然可以使用 thread multi-tasking (multi-threading), with the caveat that only one thread can typically execute at once due to the lack of multiple execution units. Without multiple execution units (hardware multi-threading), the hardware relies on a "software multi-threading" 由内核定义的策略——低级操作系统软件来确定要做什么执行和时间。

Preemption is a strategy that involves a more active shepherding (so to speak) these multiple streams of execution along a single path commonly implement in part via the use timer based interrupts. The opposite of preemption -- cooperative scheduling -- 采用更 laissez-faire 的方法,由活动线程来发出完成信号。

因此,协作调度方案允许一个线程进程的线程持有唯一的计算资源(在本例中)更长时间:

但是,如果这种方案中的活动线程试图永远保持活动状态怎么办?本质上,这就是这里发生的事情。

自旋锁是主动等待锁定请求的资源。该线程将只是坐在那里等待任何其他线程锁定它想要放弃的资源。由于文本表明硬件情况一次只允许一个活动线程,如果请求的资源被锁定,这意味着它被一个非活动线程锁定。

如果没有抢占,则由线程决定何时停止执行。因此,当活动线程自旋锁时,它将永远坐在那里——这就是所谓的挂起。要停止这种情况,用户可能会被迫物理关闭系统以清除 cache/dynamic 内存。

抢占式调度线程实现为time slices. When accessing a particular resources is requisite before further work can be complete in a thread the spinlock——忙等待——是有道理的。

通过抢占,内核将自动force context switch after a specified amount of time, so even with a single CPU there won't be a hang. Eventually the thread with the resource lock 获得一些时间并释放其资源。当自旋锁线程获得下一个调度时间时,它将能够锁定资源并继续。

总的来说,这意味着更少的挂起。

但是,自旋锁仍然会遇到更复杂的抢占式调度问题,例如死锁...当两个线程各自被自旋锁同时持有彼此的资源时:

但是,通过内核对资源锁定请求的保护通常可以避免这种情况。

在一个完美的世界中,协作调度与精心设计的线程可能会导致关键进程的执行速度更快一些。因此,在像 Mac OS 和 Windows 3.x 这样的瘦老 OSes 中,这是一种常见的方法。但是,随着计算需求的增加,避免协作调度的缺点变得越来越困难,因此几乎所有现代操作系统内核都使用抢占式调度程序。