当存在上下文切换时,获取锁的开销是否取决于操作系统计时器分辨率?

4
假设线程1使用lock(lockObj)语句尝试在lockObj对象上获取锁,但此时该对象已被线程2锁定。那么线程1会被阻塞,对吗?
现在假设在此阻塞期间发生了上下文切换,因为有其他线程和应用程序正在等待运行。线程1再次处于Running状态并能够获取锁的耗时是否取决于操作系统计时器分辨率(例如,在Windows 7上默认为15.6毫秒)?
如果上面问题的答案是肯定的,那么我还有一个疑问:
很容易创建一个简单的程序,使用Stopwatch测试Thread.Sleep(1)的平均开销,并得出它收敛于操作系统计时器分辨率(例如15.6ms)。但我发现很难创建一个程序来获取相同结论的lock语句。主要是因为:
1)很难确保尝试获取锁的线程将始终被阻塞(或至少知道它何时在获取锁之前被阻塞);
2)我不知道何时总是可以强制进行上下文切换,当当前运行的线程阻塞时是否总是会进行上下文切换?
任何帮助都将不胜感激。

不,如果那样的话,线程会表现得相当差。定时器受速率影响,而不是同步。 - Hans Passant
所以,基本上你的意思是当一个线程因为等待获取锁而被阻塞时,它不会被重新调度在下一个操作系统时间片中进行测试,以检查对象上的锁是否已经释放。还有另一种机制,使得阻塞的线程在锁对象释放时立即意识到,并使该线程再次进入运行状态? - Marcos Arruda
2
它的工作方式正好相反。当同步对象被释放时,操作系统会检查是否有任何人在等待它。如果是这样,那么该线程将被解除阻塞,并提高其优先级。通常足以让线程获取一个核心。 - Hans Passant
1个回答

0
假设线程1尝试使用lock(lockObj)语句在lockObj对象上获取锁,但是在线程1尝试获取锁时,该对象已被线程2锁定。线程1会被阻塞,对吗?
是的。
现在假设在此阻塞期间发生了上下文切换,因为有其他线程和应用程序等待运行。直到线程1再次处于Running状态并能够获取锁的经过时间是否取决于操作系统计时器分辨率(例如:Windows 7上默认为15.6毫秒)?
不直接取决于操作系统计时器分辨率。一般来说,当线程1被阻塞的等待对象变为信号状态时,线程1将立即变为就绪状态。此时,操作系统调度算法将运行,并且如果有空闲核心或其优先级足以允许其包含在可用核心的线程集中,则将线程1设置为运行状态。可能会出现定时器中断巧合地到达并设置另一个高优先级的“线程3”准备好,从而防止线程1运行,但这与“获取锁取决于操作系统计时器分辨率”相去甚远。

如果有一个核心可以自由运行线程1,我经验性地发现,在我的Windows系统上,它在来自线程2的信号后运行约7微秒 - 不是15.6毫秒或任何其他时间。

如果线程1必须等到下一个定时器中断才能运行某些信号之后,性能将非常糟糕。没有必要等待 - 操作系统已经通过线程2的信号进入了操作系统,并且操作系统决定在那个时间运行哪组线程。它可能不会立即运行线程1,因为所有核心都已经运行更高优先级的线程,它可能会抢占线程2,因为线程1具有更高的动态优先级,或者它可能通过使用其互处理器通信驱动程序向另一个核心发出硬件中断来抢占在另一个核心上运行的另一个线程。在您的情况下,定时器中断和“量子”东西基本上是无关紧要的。

不要过分关注“量子”概念(这是一个愚蠢的名称,因为“量子”应该是不可分割的,而线程很少因为I/O和线程间信号而运行精确的定时器驱动间隔),相反,考虑一个状态机,其输入是硬件中断和系统调用,输出是在核心上运行的一组线程。硬件定时器中断只是可以改变正在运行的线程集的其中之一。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接