假设线程1试图使用lock(lockObj)
语句获取lockObj对象的锁,但在线程1试图获取锁的那一刻,该对象已经被thread2锁定。线程1会阻止,对吗?
现在假设在这个阻塞期间,有一个上下文切换,因为还有其他线程和应用程序在等待运行。线程1再次处于运行状态并能够获取锁之前的运行时间是否取决于操作系统计时器分辨率(例如:Windows 7上的默认值15.6毫秒)?
如果以上问题的答案是肯定的,那么我还有另一个疑问:
使用Stopwatch可以很容易地创建一个简单的程序来测试Thread.Sleep(1)
的平均开销,并得出它收敛于操作系统计时器分辨率(例如15.6ms)的结论。但是我发现很难创建一个程序来获得与lock语句相同的结论。主要是因为:
1) 很难确保试图获取锁的线程总是阻塞(或者至少在获取锁之前知道它什么时候阻塞了);
2) 每当线程试图获取锁块时,我不知道如何强制上下文切换。当当前运行的线程阻塞时,是否总是有上下文切换?
任何帮助都将不胜感激。
假设线程1试图使用lock(lockObj)语句,但此对象已被锁定线程2在线程1试图获取其锁定的时刻1会挡住,对吧?
是的。
现在假设在这个阻塞期间,有一个上下文切换,因为还有其他线程和应用程序在等待运行。是直到线程1再次处于运行状态并且能够获取依赖于操作系统计时器分辨率的锁(例如:默认值在Windows 7上为15.6毫秒)?
不是直接的,不是。一般来说,线程1会在被阻塞的等待对象发出信号后立即准备就绪。届时,操作系统调度算法将运行,线程1将被设置为在内核上运行,如果内核是空闲的,或者线程1的优先级足以允许它被包括在线程集中,以便在可用内核上运行。定时器可能会打断我的同时到达,并将另一个高优先级的"线程3"设置为就绪状态,从而阻止线程1运行,但这与"获取锁取决于操作系统定时器分辨率"的说法相去甚远。
如果有一个核心可以自由运行线程1,我根据经验发现,它在我的Windows系统上的线程2发出信号后运行~7us——几微秒,而不是15.6毫秒或类似的时间
如果线程1必须等到下一个定时器中断后才能运行某个信号,那么性能将非常糟糕。它不需要等待——操作系统已经通过来自线程2的信号进入,操作系统决定此时运行哪组线程。它可能不会立即运行线程1,因为所有核都已经在运行更高优先级的线程,它可能会抢占线程2,因为线程1具有更高的动态优先级,或者它可能会通过使用其处理器间通信驱动程序向另一个核发出硬件中断来抢占在另一个核心上运行的另一个线程。定时器中断和"量子"的东西在你的场景中基本上是无关的。
尽量不要拘泥于"量子"概念(这是一个愚蠢的名字,因为"量子"应该是不可分割的,由于I/O和线程间信令,线程很少在精确的定时器驱动间隔内运行),而应该考虑一个状态机,它的输入是硬件中断和系统调用,输出是一组在内核上运行的线程。硬件定时器中断只是可以更改正在运行的线程集的输入之一。