问题描述
当多个线程请求同一个对象上的锁时,CLR 是否保证将按照它们被请求的顺序获取锁?
When multiple threads request a lock on the same object, does the CLR guarantee that the locks will be acquired in the order they were requested?
我写了一个测试看看这是不是真的,它似乎表明是的,但我不确定这是否是确定的.
I wrote up a test to see if this was true, and it seems to indicate yes, but I'm not sure if this is definitive.
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 滴答
0 sleeping for 49979998 ticks
进入:1
进入:2
进入:3
进入:4
进入:5
进入:6
进入:7
进入:8
进入:9
0 退出锁定
1 被锁定
1 睡眠 5001 滴答声
1 sleeping for 5001 ticks
1 个退出锁
2 被锁定
2 睡眠 5001 滴答声
2 sleeping for 5001 ticks
2 退出锁
3 被锁定
3 睡眠 5001 滴答声
3 sleeping for 5001 ticks
3 退出锁
4 被锁定
4 睡眠 5001 滴答声
4 sleeping for 5001 ticks
4 退出锁
5 被锁定
5 睡眠 5001 滴答声
5 sleeping for 5001 ticks
5 退出锁
6 被锁定
6 退出锁
7 被锁定
7 退出锁
8 被锁定
8 退出锁
9 被锁定
9 退出锁
推荐答案
IIRC,很有可能按这个顺序排列,但不能保证.我相信至少在理论上存在一个线程会被虚假唤醒的情况,注意它仍然没有锁,然后走到队列的后面.这可能仅适用于 Wait
/Notify
,但我偷偷怀疑它也适用于锁定.
IIRC, it's highly likely to be in that order, but it's not guaranteed. I believe there are at least theoretically cases where a thread will be woken spuriously, note that it still doesn't have the lock, and go to the back of the queue. It's possible that's only for Wait
/Notify
, but I have a sneaking suspicion it's for locking as well.
我肯定不会依赖它 - 如果您需要按顺序发生,请建立一个 Queue<T>
或类似的东西.
I definitely wouldn't rely on it - if you need things to occur in a sequence, build up a Queue<T>
or something similar.
我刚刚在 Joe Duffy 的 Concurrent基本同意的Windows编程:
I've just found this within Joe Duffy's Concurrent Programming on Windows which basically agrees:
因为监视器在内部使用内核对象,所以它们表现出与操作系统同步机制也表现出的大致相同的 FIFO 行为(在前一章中描述).监视器是不公平的,因此如果另一个线程在唤醒的等待线程尝试获取锁之前尝试获取锁,则允许偷偷摸摸的线程获取锁.
大致 FIFO"位是我之前想到的,而偷偷摸摸的线程"位进一步证明了您不应该对 FIFO 排序做出假设.
The "roughly-FIFO" bit is what I was thinking of before, and the "sneaky thread" bit is further evidence that you shouldn't make assumptions about FIFO ordering.
这篇关于lock() 是否保证按请求的顺序获得?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!