我要求一段代码一次只能由一个线程运行(单个资源锁)。
C# 中的lock(object)
语句允许这样做。但是,它不会保留对锁的请求顺序。
例如,考虑下面的 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);
访问的实际授予不是完美的顺序 (1->100) 或不是 FIFO。然而,似乎确实存在“早进早出”的 EIEO 模式(也许由堆运行?)。
问题是:什么决定了锁的授予顺序,是否可以依靠它不饿死一个不幸的线程?
更新:这个答案解释了它。这是相关的引用(Joe Duffy 在 Windows 上的并发编程):
因为监视器在内部使用内核对象,所以它们表现出与 OS 同步机制也表现出的大致相同的 FIFO 行为(在前一章中描述)。监视器是不公平的,因此如果另一个线程在唤醒的等待线程尝试获取锁之前尝试获取锁,则允许偷偷摸摸的线程获取锁。