Lock语句如何确定授予对象访问权限的顺序?

Man*_*ndo 1 c# multithreading synchronization

我要求一部分代码一次只能由一个线程运行(单个资源锁定).

lock(object)C#中的语句允许这样做.但是,它不会保留对锁的请求顺序.

例如,考虑下面的100个线程启动,其中编号的线程尝试按顺序锁定挂锁:

    for (int i = 0; i < 100; i++)
             {

            (new Thread(delegate(object index) 
               {
                  int name = (int) index;
                  byte[] len = new byte[2];

                  Console.WriteLine(string.Format("Thread:{0} going for lock. ",
                      name));
                  lock (padlock)
                  {

                     rnd.GetBytes(len);
                     ushort l = BitConverter.ToUInt16(len, 0);
                     Console.WriteLine(string.Format("Thread:{0} sleeping: {1}", 
                       name, l));
                     Thread.Sleep(l);
                  }
            })).Start(i);
Run Code Online (Sandbox Code Playgroud)

实际授予访问权限的顺序并不完美(1-> 100)或NOT FIFO.然而,似乎确实存在"早期早期"EIEO模式(可能由堆运行?).

问题是:什么决定了锁定授予顺序,是否可以依赖于不使不幸的线程挨饿?

更新:这个答案解释了它.这是相关的引用(Joe Duffy在Windows上的并发编程):

因为监视器在内部使用内核对象,所以它们表现出与OS同步机制也表现出的相同的粗略FIFO行为(在前一章中描述).监视器是不公平的,因此如果另一个线程试图在唤醒的等待线程尝试获取锁之前获取锁,则允许偷偷摸摸的线程获取锁.

Eri*_*ert 5

Servy的答案当然是正确的.一些额外的细节:

是什么决定了锁定授予顺序?

最终,操作系统.

是不是可以依赖不饿的一个不幸的线程?

饥饿不太可能,但可能.如果你不能忍受很小的饥饿机会,你需要一些比锁更复杂的东西.

我还注意到锁是"不公平的",因为你可以在锁中有一个线程,八个线程在等待,锁中的线程离开,一个没有等待的第十个线程请求锁并获得它"切断线".Joe给出了一个有趣的分析,为什么Windows现在在这里使用"不公平"的锁定分配策略,如果这个主题让你感兴趣:

http://joeduffyblog.com/2006/12/14/anticonvoy-locks-in-windows-server-2003-sp1-and-windows-vista/