Sam*_*eff 60 .net c# synchronization locking
当多个线程请求锁定同一个对象时,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);
}
}
Run Code Online (Sandbox Code Playgroud)
打印:
输入: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退出锁
Jon*_*eet 73
IIRC,它极有可能按顺序排列,但不能保证.我相信至少在理论上情况下,一个线程将被虚假地唤醒,注意它仍然没有锁定,并且转到队列的后面.这可能只适用于Wait
/ Notify
,但我也有一种潜在的怀疑,那就是锁定.
我绝对不会依赖它 - 如果你需要按顺序发生事情,建立一个Queue<T>
或类似的东西.
编辑:我刚刚在Joe Duffy的Windows并发编程中找到了这个基本同意:
因为监视器在内部使用内核对象,所以它们表现出与OS同步机制也表现出的相同的粗略FIFO行为(在前一章中描述).监视器是不公平的,因此如果另一个线程试图在唤醒的等待线程尝试获取锁之前获取锁,则允许偷偷摸摸的线程获取锁.
"粗略FIFO"位是我之前想到的,"偷偷摸摸的线程"位进一步证明你不应该对FIFO排序做出假设.
Mic*_*urr 10
记录该lock
语句是为了使用Monitor
该类来实现它的行为,而Monitor类的文档没有提及(我可以找到)公平性.因此,您不应该依赖于请求顺序获取的请求锁.
事实上,杰弗里里希特的一篇文章表明其实lock
并不公平:
当然 - 这是一篇旧文章所以事情可能已经发生了变化,但鉴于Monitor
课堂合同中没有关于公平性的承诺,你需要假设最坏的情况.