【发布时间】:2022-01-14 13:54:29
【问题描述】:
我有以下代码
class Program
{
static SpinLock sl = new SpinLock();
public static void Foo(object arg)
{
bool r = false;
sl.Enter(ref r);
}
public static void Main(string[] args)
{
bool r = false;
sl.Enter(ref r);
ThreadPool.QueueUserWorkItem(Foo);
Thread.Sleep(5000);
sl.Exit();
Thread.Sleep(5000);
}
}
当我执行它时,我看到在整个程序运行期间大约有 0% 的 CPU 负载。由于在sl.Enter() 调用中旋转,我预计会看到一些 CPU 烧毁,但事实并非如此。
根据SpinLock source,它在底层使用SpinWait,而后者又在某些时候实际调用Thread.Sleep(1)。
这是否意味着 SpinLock 和 SpinWait 都不是真正的“微调器”,而是仍然依靠操作系统调度程序来产生一些 CPU 份额?
编辑
问题可以用以下方式重新表述:
使用忙循环可确保一个线程释放锁与另一个线程获取锁之间的时间最短。在这方面我可以依靠SpinLock/SpinWait吗?据我所知,答案是否,因为Sleep 至少持续了 1 微秒,并且在此期间可能会在某处释放锁。
【问题讨论】:
-
来自docs:“
SpinWait封装了纺丝和真正屈服的良好组合。” -
@GuruStron 我认为这句话与上一句有关,“在单处理器机器上,总是使用产量而不是忙等待”,但是我在 SMP 机器上运行我的代码。跨度>
-
我对问题进行了重新表述,使其不涉及基于意见的答案。
-
SpinLock 中的基本方法是优化上下文切换,在放弃之前旋转一段时间,让操作系统阻塞线程以允许另一个线程运行。 “一段时间”需要小于上下文切换成本的两倍才能实际优化任何东西。上下文切换需要 3,000 到 15,000 个处理器周期,给予或接受。程序休眠 10 秒,或大约 30,000,000,000 个周期。所以你会期望看到 100% * 2 * 15,000 / 30,000,000,000 = 0.0001% cpu 负载。是的,看起来像 0。
标签: c# multithreading spinlock