在c#中设置一个简单的属性是不线程安全的
本文关键字:属性 简单 安全 线程 一个 设置 | 更新日期: 2023-09-27 18:06:03
我已经阅读了大量关于如何使属性线程安全的讨论和示例。页面上有一个线程安全包装器类
给出的例子是:
internal class MyThreadSafeCass
{
// *** Lock ***
private object PropertyLock = new object();
// *** Property ***
private int m_Property = 0;
// *** Thread-safe access to Property using locking ***
internal int Property
{
get
{
lock (PropertyLock)
{
return m_Property;
}
}
set
{
lock (PropertyLock)
{
m_Property = value;
}
}
}
}
很清楚这里发生了什么,锁在做什么,但我很难理解为什么需要它。为什么下面的不是线程安全?哪里会出错呢?
internal class MyThreadSafeCass
{
// *** Property ***
private int m_Property = 0;
// *** Thread-safe access to Property using locking ***
internal int Property
{
get
{
return m_Property;
}
set
{
m_Property = value;
}
}
}
一个表达式:m_Property++;在多个线程中,parallel返回不同的值。特别是在多核cpu上。
- 旧值被加载到cpu的缓存中。
- 该值将由cpu增加
- 新值将被保存回内存。
的例子:
- core one将加载值为10
- 核心2将与核心1同时加载值为10
- 均加1(值为11)
- 都将数据保存回内存
- 结果将是11.
- 但你期望12
查看详细信息
@Enigmativity通过链接到这个关于跳过锁的博客而获得了荣誉(如果不是分数,不幸的是),这个博客又链接到这个关于CPU重新排序优化的博客,这是答案的真正内容。
总之,cpu可以(并且确实)对代码进行优化,包括改变读/写的执行顺序。这些更改保证在执行它们的线程内保持一致且不易察觉。然而,它们不能(不能)保证访问共享内存的多个线程之间的一致性。锁,如第一个问题中的示例所示,对访问这个共享内存施加限制,从而恢复一致性。
正如我所说,这是一个总结。我不能在上面链接的博客中添加任何内容,所以我会推迟任何有兴趣知道完整答案的人跟随这些链接。
@Enigmativity,如果你这样发帖,我仍然会接受你的回答。否则,我将接受这个答案并关闭它。