假设一个类有一个由多个线程访问的字段。这只会递增或递减。public int counter
int
要增加此字段,应使用哪种方法,为什么?
lock(this.locker) this.counter++;
,Interlocked.Increment(ref this.counter);
,counter
public volatile
现在我已经发现了,我已经删除了许多语句和使用.但是有理由不这样做吗?volatile
lock
Interlocked
网友回答:
编辑:正如评论中所指出的,这些天我很高兴用于单个变量的情况,这显然是可以的。当它变得更复杂时,我仍然会恢复到锁定…Interlocked
当您需要递增时,使用将无济于事——因为读取和写入是单独的指令。另一个线程可能会在您读取之后但在您写回之前更改该值。volatile
就我个人而言,我几乎总是锁定 – 以一种明显正确的方式比波动性或互锁增量更容易正确。就我而言,无锁多线程适用于真正的线程专家,我不是其中之一。如果 Joe Duffy 和他的团队构建了漂亮的库,这些库可以并行化事物,而不会像我构建的东西那样多地锁定,那真是太棒了,我会在心跳中使用它——但是当我自己做线程时,我会尽量保持简单。
网友回答:
将访问修饰符更改为
counter
public volatile
正如其他人所提到的,这本身实际上根本不安全。关键是,在多个CPU上运行的多个线程可以并且将缓存数据并重新排序指令。volatile
如果不是 ,并且 CPU A 递增一个值,则 CPU B 可能直到一段时间后才真正看到该递增的值,这可能会导致问题。volatile
如果是,这只会确保两个CPU同时看到相同的数据。它根本不会阻止它们交错读取和写入操作,这是您要避免的问题。volatile
lock(this.locker) this.counter++
;
这是安全的(前提是您记得访问的其他任何地方)。它可以防止任何其他线程执行由 保护的任何其他代码。
使用锁还可以防止上述多 CPU 重新排序问题,这很好。lock
this.counter
locker
问题是,锁定很慢,如果您在其他不真正相关的地方重用,那么您最终可能会无缘无故地阻塞其他线程。locker
Interlocked.Increment(ref this.counter);
这是安全的,因为它有效地在“一次点击”中读取、增量和写入,不能中断。因此,它不会影响任何其他代码,您也不需要记住在其他地方锁定。它也非常快(正如MSDN所说,在现代CPU上,这通常是单个CPU指令)。
但是,我不完全确定它是否绕过其他 CPU 重新排序的东西,或者您是否还需要将易失性与增量相结合。
联锁笔记:
由于不能防止这些类型的多线程问题,它有什么用?一个很好的例子是说你有两个线程,一个总是写入一个变量(比如),另一个总是从同一个变量读取。volatile
queueLength
如果不是易失性的,线程 A 可能会写入五次,但线程 B 可能会将这些写入视为延迟(甚至可能以错误的顺序)。queueLength
一种解决方案是锁定,但您也可以在这种情况下使用易失性。这将确保线程 B 始终看到线程 A 编写的最新内容。但请注意,只有当你有从不读书的作家和从不写作的读者,并且你正在写的东西是一个原子值时,这个逻辑才有效。执行单个读取-修改-写入后,需要转到联锁操作或使用锁定。
网友回答:
“” 不替换 !它只是确保变量没有缓存,而是直接使用。volatile
Interlocked.Increment
递增变量实际上需要三个操作:
Interlocked.Increment
将所有三个部分作为单个原子操作执行。
模板简介:该模板名称为【多个线程访问的字段,这只会递增或递减,要增加此字段,应使用哪种方法,为什么?】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【C#】栏目查找您需要的精美模板。