当多个线程请求同一个对象上的锁时,CLR是否保证按照请求的顺序获取锁?
我写了一个测试,看看这是不是真的,这似乎表明是的,但我不确定这是否确定。
class LockSequence
{
private static readonly object _lock = new object();
private static DateTime _dueTime;
public static void Test()
{
var states = new List<State>();
_dueTime = DateTime.Now.AddSeconds(5);
for (int i = 0; i < 10; i++)
{
var state = new State {Index = i};
ThreadPool.QueueUserWorkItem(Go, state);
states.Add(state);
Thread.Sleep(100);
}
states.ForEach(s => s.Sync.WaitOne());
states.ForEach(s => s.Sync.Close());
}
private static void Go(object state)
{
var s = (State) state;
Console.WriteLine("Go entered: " + s.Index);
lock (_lock)
{
Console.WriteLine("{0,2} got lock", s.Index);
if (_dueTime > DateTime.Now)
{
var time = _dueTime - DateTime.Now;
Console.WriteLine("{0,2} sleeping for {1} ticks", s.Index, time.Ticks);
Thread.Sleep(time);
}
Console.WriteLine("{0,2} exiting lock", s.Index);
}
s.Sync.Set();
}
private class State
{
public int Index;
public readonly ManualResetEvent Sync = new ManualResetEvent(false);
}
}
指纹:
进入:0 0锁 0睡49979998只蜱 进入:1 进入:2 进入:3 进入:4 进入:5 进入:6 进入:7 进入:8 进入:9 0退出锁 1把锁 1只睡5001只蜱 1出锁 2门锁定 2只睡5001只蜱 2退出锁 3锁 3只睡5001只蜱 3出锁 4锁 4只睡5001只蜱 4出锁 5把锁 5只睡5001只蜱 5出锁 6把锁 6出锁 7把锁 7出口锁 8把锁 8出锁 9把锁 9出口锁
发布于 2010-11-19 19:59:48
IIRC,这很有可能是按这个顺序进行的,但不能保证。我相信至少在理论上,线程会被伪造地唤醒,注意它仍然没有锁,然后转到队列的后面。这可能只适用于Wait
/Notify
,但我有一种潜移默化的怀疑,它也是用来锁定的。
我绝对不会依赖它--如果您需要在一个序列中发生一些事情,那么构建一个Queue<T>
或类似的东西。
编辑:我刚刚在乔·达菲的Windows环境下的并发编程中发现了这一点,它基本上同意:
由于监视器在内部使用内核对象,因此它们表现出与OS同步机制(在前一章中描述)大致相同的FIFO行为。监视器是不公平的,因此,如果另一个线程在唤醒等待线程试图获取锁之前试图获取该锁,则允许该秘密线程获取一个锁。
“粗略的FIFO”位是我以前想过的,而“狡猾的线程”位进一步证明了你不应该对FIFO排序做出假设。
发布于 2015-06-01 21:46:14
正常的CLR锁不能保证是FIFO。
但是,有一个这个答案中的QueuedLock类 将提供一个有保证的FIFO锁定行为。
发布于 2010-11-19 20:11:18
lock
语句是用来使用Monitor
类来实现其行为的,而Monitor类的文档没有提到(我可以找到的)公平性。因此,您不应依赖按请求顺序获取的请求锁。
事实上,Jeffery Richter的一篇文章指出,实际上lock
是不公平的:
当然--这是一篇老掉牙的文章,所以事情可能已经发生了变化,但考虑到Monitor
类的合同中没有关于公平性的承诺,你需要假设最坏的情况。
https://stackoverflow.com/questions/4228864
复制相似问题