我正在阅读以下文章:http: //msdn.microsoft.com/en-us/magazine/cc817398.aspx "解决你的多线程代码中的11个可能的问题"作者:Joe Duffy
它提出了一个问题:"我们需要在用多线程代码读取它时锁定.NET Int32吗?"
据我所知,如果它是32位SO中的Int64,它可能会撕裂,正如文章中所解释的那样.但对于Int32,我想到了以下情况:
class Test
{
private int example = 0;
private Object thisLock = new Object();
public void Add(int another)
{
lock(thisLock)
{
example += another;
}
}
public int Read()
{
return example;
}
}
Run Code Online (Sandbox Code Playgroud)
我没有看到在Read方法中包含锁的原因.你呢?
更新基于答案(由Jon Skeet和ctacke提供)我理解上面的代码仍然容易受到多处理器缓存的影响(每个处理器都有自己的缓存,与其他处理器不同步).所有这三个修改都解决了这个问题:
而且我也认为"易变"是最优雅的解决方案.
在.NET中的lock关键字是语法糖各地Monitor.Enter及Monitor.Exit,所以你可以说,这段代码
lock(locker)
{
// Do something
}
Run Code Online (Sandbox Code Playgroud)
是相同的
Monitor.Enter(locker);
try
{
// Do Something
}
finally
{
Monitor.Exit(locker);
}
Run Code Online (Sandbox Code Playgroud)
但是,.NET框架还包括MemoryBarrier以类似方式工作的类
Thread.MemoryBarrier();
//Do something
Thread.MemoryBarrier();
Run Code Online (Sandbox Code Playgroud)
我很困惑,当我想用Thread.MemoryBarrier在lock/ Monitor版本?我更加困惑的是线程教程,它表明它们的功能相同.
据我所知,可见的区别是不需要锁定对象,我想使用Monitor你可以跨线程做一些事情MemoryBarrier在一个线程上.
我的直觉告诉我,另一个关键的区别是MemoryBarrier仅变量而不是方法.
最后这与现有问题无关何时在线程安全锁定代码中使用'volatile'或'Thread.MemoryBarrier()'?(C#),因为它专注于volatile我理解其使用的关键字.
为了实现多线程应用程序的无锁代码,我使用了volatile变量,
理论上:该volatile关键字仅用于确保所有线程都能看到volatile变量的最新值; 因此,如果线程A更新变量值并且线程B在该更新发生之后读取该变量,它将看到最近从线程A写入的最新值.正如我在Nutshell书中的C#4.0中读到的那样,这是不正确的,因为
应用volatile不会阻止写入后读取交换.
可以通过Thread.MemoryBarrier()在每次获取volatile变量之前放置来解决这个问题:
private volatile bool _foo = false;
private void A()
{
//…
Thread.MemoryBarrier();
if (_foo)
{
//do somthing
}
}
private void B()
{
//…
_foo = true;
//…
}
Run Code Online (Sandbox Code Playgroud)
如果这解决了问题; 考虑我们有一个while循环,它依赖于其中一个条件的值; Thread.MemoryBarrier()在while循环之前放置是解决问题的正确方法吗?例:
private void A()
{
Thread.MemoryBarrier();
while (_someOtherConditions && _foo)
{
// do somthing.
}
}
Run Code Online (Sandbox Code Playgroud)
为了更准确,我希望_foo变量在任何时候任何线程要求它时给出最新的值; 因此,如果Thread.MemoryBarrier()在调用变量之前插入修复问题,那么我可以使用 …
static在C#中对多线程环境中的成员执行锁定读/写访问的最安全(和最短)方法是什么?
是否可以在类级别上执行线程安全锁定和解锁(因此,每次需要静态成员访问时,我都不会继续重复锁定/解锁代码)?
编辑:示例代码会很棒:)
编辑:我应该使用volatile关键字或Thread.MemoryBarrier()来避免多处理器缓存还是不必要?根据Jon Skeet的说法,只有那些会让其他处理器看到变化吗?(另被问及这在这里).