Skip to main content
 首页 » 编程设计

c#之资源争用之并不总是使用锁

2024年01月24日37grandyang

我看到杰弗里里希特 video (点击查看确切的行)他说:

It is always better to use Monitor.Enter and Monitor.Lock over Event-wait-handles or Semaphore etc because they (monitor.X) use kernel object , but they only use them if there's contention. and if there's no contention , they dont use those objects.

我可能在这里遗漏了一些东西,但是当我这样做的时候:

lock(myObj) 
{ 
 ... 
} 

我推测可能有不止一个线程想要进入临界区。
那么,根据上面的信息,如果没有争用,锁就不会被使用? (如果1ms后另一个线程即将进入怎么办?)

请您参考如下方法:

是的,Monitor 类在 CLR 中进行了非常好的优化。如果没有其他线程已经拥有监视器,那么它非常便宜。您甚至不需要为额外的存储付费,锁定状态存储在对象中的一个字段中,每个对象都已经可用,是对象 header 的一部分。

Monitor.Enter() 方法通过首先检查锁是否已被同一线程拥有来避免进入操作系统代码。这使得它可以重入,如果是这种情况,它只会增加锁定计数。接下来,它尝试使用 Interlocked.CompareExchange() 的等价物来获取锁,Interlocked.CompareExchange() 是一种在任何处理器上都非常便宜的原语。它的 x86 版本值得注意的是实际上根本没有采用总线锁,您可以在 this answer 中查看它的代码。 .

如果这不起作用,那么操作系统需要介入,因为现在重要的是它可以进行线程上下文切换以在释放锁时唤醒线程备份。 Windows 非常喜欢选择一个正在等待 OS 同步对象的线程,以确保它尽快重新开始运行。底层对象是一个简单的事件,一个非常廉价的操作系统对象。它还负责公平性,等待线程被放入队列并以先进先出的顺序释放。我在 this answer 中记录了底层 CLR 代码.