Oha*_*der 5 c# multithreading locking memory-barriers
通过锁定助手,我指的是可以通过using
语句实现锁定的一次性对象.例如,考虑Jon Skeet的MiscUtilSyncLock
类的典型用法:
public class Example
{
private readonly SyncLock _padlock;
public Example()
{
_padlock = new SyncLock();
}
public void ConcurrentMethod()
{
using (_padlock.Lock())
{
// Now own the padlock - do concurrent stuff
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,考虑以下用法:
var example = new Example();
new Thread(example.ConcurrentMethod).Start();
Run Code Online (Sandbox Code Playgroud)
我的问题是这个 - 因为example
是在一个线程上创建并ConcurrentMethod
在另一个线程上调用,所以ConcurrentMethod
线程不会忘记_padock
在构造函数中的赋值(由于线程缓存/读写重新排序),因而抛出一个NullReferenceException
(在_padLock
本身)?
我知道锁定Monitor
/ lock
具有内存障碍的好处,但是当使用这样的锁定助手时,我无法理解为什么会有这样的障碍得到保证.在这种情况下,据我所知,构造函数必须修改:
public Example()
{
_padlock = new SyncLock();
Thread.MemoryBarrier();
}
Run Code Online (Sandbox Code Playgroud)
编辑 Hans Passant认为创建线程意味着内存障碍.那怎么样:
var example = new Example();
ThreadPool.QueueUserWorkItem(s => example.ConcurrentMethod());
Run Code Online (Sandbox Code Playgroud)
现在一个线程不一定被创建......
Bri*_*eon 10
不,您不需要做任何特别的事情来保证创建内存障碍.这是因为几乎所有用于获取在另一个线程上执行的方法的机制都会在调用线程上生成一个释放栅栏屏障,并在工作线程上生成一个aquire-fence屏障(实际上它们可能是完整的栅栏障碍).因此,无论是QueueUserWorkItem
或Thread.Start
将自动插入必要的障碍.你的代码是安全的.
此外,作为切向感兴趣的问题Thread.Sleep
也会产生记忆障碍.这很有趣,因为有些人天真地Thread.Sleep
用来模拟线程交错.如果使用此策略对低锁定代码进行故障排除,则可以很好地掩盖您尝试查找的问题.
归档时间: |
|
查看次数: |
721 次 |
最近记录: |