与仅有一个对象相比,锁定多个不同对象是否具有明显的影响?

Noc*_*ock 8 .net c# multithreading

我不知道问题是不是愚蠢,锁定和监视器对我来说是一个黑盒子.

但我正处理的情况是,我可以使用相同的锁定对象来锁定所有时间,或使用无限数量的对象来锁定更精细的粒度.

我知道第二种方法会减少锁争用,但我可能最终使用10K对象作为锁,我不知道它是否有影响.

底线:太多锁会伤到锁定还是没有影响?

编辑

我写了一个维护对象图的lib,数量可能非常高.目前它不是线程安全的,主要是因为Eric在他的评论中说.

我最初认为,如果用户想要做一些多线程,那么他/她将不得不处理锁定.

但是现在我想知道如果我必须使它成为线程安全的,那么最好的方法是什么(请注意,使它成为线程安全对我来说不是一个简单而轻松的选择,因此测试两种解决方案是我不能轻易做到的事情)?

由于目的是使图形的每个对象都是线程安全的,所以当我想访问/修改其属性时,我可以使用该对象的实例进行锁定.我知道这是减少争用的最佳方法,但我不知道它是否会扩展到只有一个锁定整个图形.

我知道需要考虑很多,有多少线程,特别是(我认为)一次有多个线程访问/更改对象的机会(我估计它非常低).但在这种情况下,我无法找到有关锁及其开销的准确信息.

Noc*_*ock 5

为了更清楚地了解正在发生的事情,我查看了共享源公共语言基础结构中Monitor该类的源代码及其对应的 C++clr/src/vm/syncblk.cpp了 Microsoft 发布。

回答我自己的问题:不,拥有很多锁不会以我能想到的任何有害方式造成伤害。

我学到的是:

1) 已被同一线程占用的锁被“几乎免费”处理。

2)第一次使用的锁基本上是一个InterlockedCompareExchange.

3) 多个等待锁的线程的跟踪成本相当低(维护一个链表,O(1) 复杂度)。

4) 等待锁释放的线程是迄今为止成本最高的用例,实现首先自旋等待尝试退出,但如果这还不够,则会发生线程切换,使线程进入睡眠状态,直到互斥体发出信号由于锁定释放而唤醒的时间。

我通过挖掘 2) 得到了我的答案:如果您总是使用相同的对象或 10K 不同的对象进行锁定,则基本相同(第一次锁定给定对象时会执行额外的初始化,但这还不错) . InterlockedCompareExchange 不关心在相同或不同的内存位置(AFAIK)上被调用。

到目前为止,争用是最关键的问题。有很多锁会减少(在我的情况下)竞争的机会,所以这只能是一件好事。

1)也是一个重要的经验教训:如果我为每个属性更改/访问锁定/解锁,我可以通过先锁定对象,然后更改许多属性并释放锁定来提高性能。这样将只有一个 InterlockedCompareExchange 并且在属性更改/访问的实现中的锁定/解锁只会增加一个内部计数器。

要深入挖掘,我必须找到有关 InterlockedCompareExchange 实现的更多信息,我认为它依赖于 CPU 特定的汇编指令......