当多个线程在同一个对象上请求锁时,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滴答声

GO输入:1

进入:2

进入:3

进入:4

开始:5

开始:6

进入:7

Go Enter:8

Go Enter:9

0退出锁定

%1已锁定

1个5001刻度的睡眠时间

%1正在退出锁定

我有锁

2睡5001刻度

2出口锁

3.有锁

3.睡5001个蜱虫

3出口锁

4.我有锁

4.睡5001只蜱

4出口锁

5.我有锁

5.睡5001只蜱

5退出锁定

6个被锁定

6出口锁

我有锁

7出口锁

8个被锁定

8出口锁

我有锁

9出口锁

推荐答案

IIRC,顺序是highly likely,但不能保证.我相信至少在理论上会有线程被错误唤醒的情况,请注意,它仍然没有锁,并转到队列的后面.这可能只适用于Wait/Notify,但我暗自怀疑它也适用于锁定.

definitely不会依赖它-如果你需要事情按顺序发生,建立一个Queue<T>或类似的东西.

EDIT: I've just found this within Joe Duffy's Concurrent Programming on Windows which basically agrees:

因为监视器在内部使用内核对象,所以它们表现出与操作系统同步机制同样的大致FIFO行为(在前一章中描述).监视器是不公平的,因此,如果另一个线程在唤醒的等待线程try 获取锁之前try 获取锁,则允许偷偷摸摸的线程获取锁.

"粗略的FIFO"位是我之前想到的,而"鬼鬼祟祟的线程"位进一步证明了你不应该对FIFO排序进行假设.

.net相关问答推荐

如何将 signalR 添加到不同项目中的后台服务?

为什么解码后的字节数组与原始字节数组不同?

System.IO.Directory.Exists 在 LINQ 语句中失败,但在 foreach 循环中没有

将 DataRowCollection 转换为 IEnumerable

Environment.TickCount 与 DateTime.Now

为什么 .NET 中没有可序列化 XML 的字典?

Select 文件夹对话框 WPF

.Net 中的 Decimal.One、Decimal.Zero、Decimal.MinusOne 的用途是什么

为什么需要 XmlNamespaceManager?

为什么字典比列表快得多?

使用 .NET 中的代码更改桌面墙纸

DBNull 的意义何在?

C# 编译为 32/64 位,或任何 cpu?

.net 自定义配置如何不区分大小写解析枚举 ConfigurationProperty

无法使用 Unity 将依赖项注入 ASP.NET Web API 控制器

如何找到二维数组的大小?

在 .NET 中获取默认打印机的最佳方法是什么

如何以编程方式删除 WebClient 中的 2 个连接限制

如何访问 Session 变量并在 javascript 中设置它们?

在构建事件命令行中放置注释的正确方法?