相关疑难解决方法(0)

记忆障碍发生器

阅读Joseph Albahari的线程教程,以下内容被提及为内存障碍的生成器:

  • C#的lock陈述(Monitor.Enter/ Monitor.Exit)
  • Interlocked班上的所有方法
  • 使用线程池的异步回调 - 包括异步委托,APM回调和任务延续
  • 设置和等待信令构造
  • 任何依赖于信令的东西,例如启动或等待任务

此外,Hans Passant和Brian Gideon 补充了以下内容(假设其中没有一个已经符合以前的类别之一):

  • 启动或唤醒线程
  • 上下文切换
  • Thread.Sleep()

我想知道这个清单是否完整(如果完整清单甚至可以实际制作)

编辑补充建议:

  • 易失性(读数意味着获取围栏,写作意味着释放围栏)

c# memory-barriers

24
推荐指数
2
解决办法
4193
查看次数

多线程时锁定单个bool变量?

最近我在WebSite中看到了这段代码,我的问题如下:

        private bool mbTestFinished = false;

        private bool IsFinished()
        {
            lock( mLock )
            {
                return mbTestFinished;
            }
        }

        internal void SetFinished()
        {
            lock( mLock )
            {
                mbTestFinished = true;
            }
        }
Run Code Online (Sandbox Code Playgroud)

在多线程环境中,是否真的有必要锁定访问权限mbTestFinished

.net c# multithreading locking

24
推荐指数
3
解决办法
1万
查看次数

在哪里放置栅栏/内存屏障以保证新的读取/提交写入?

像许多其他人一样,我一直对易失性读/写和围栏感到困惑.所以现在我想完全理解这些是做什么的.

因此,易失性读取应该(1)表现出获取语义,(2)保证读取的值是新鲜的,即它不是缓存值.让我们关注(2).

现在,我已经读过,如果你想执行一个易失性读取,你应该在读取后引入一个获取栅栏(或一个完整的栅栏),如下所示:

int local = shared;
Thread.MemoryBarrier();
Run Code Online (Sandbox Code Playgroud)

这究竟是如何阻止读取操作使用以前缓存的值?根据栅栏的定义(不允许读取/存储在栅栏上方/下方移动),我会在读取之前插入栅栏,防止读取穿过栅栏并及时向后移动(也就是说,是缓存).

如何防止读取被及时向前移动(或后续指令被及时向后移动)保证了易失性(新鲜)读取?它有什么用?


类似地,我认为易失性写入应该在写入操作之后引入栅栏,从而阻止处理器及时向前移动写入(也就是说,延迟写入).我相信这会使处理器刷新对主存储器的写入.

但令我惊讶的是,C#实现在写入之前引入了栅栏!

[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
public static void VolatileWrite(ref int address, int value)
{
    MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
    address = value;
}
Run Code Online (Sandbox Code Playgroud)

更新

根据这个例子,显然是从"坚果壳中的C#4"中取出的,写入之后放置的栅栏2 应该强制写入立即刷新到主存储器,并且读取之前放置的栅栏3 应该保证一个新的阅读:

class Foo{
  int _answer;
  bool complete;
  void A(){
    _answer = 123;
    Thread.MemoryBarrier(); …
Run Code Online (Sandbox Code Playgroud)

.net c# multithreading volatile memory-fences

13
推荐指数
2
解决办法
1156
查看次数

并发互锁和读取是否需要内存屏障或锁定?

这是一个简单的问题,但在阅读之后我为什么需要内存屏障?我很困惑.

在下面的示例中,假设不同的线程重复调用Increment和Counter:

class Foo{
    int _counter=0;
    public int Counter 
    {
        get { return _counter; }
    }

    public void Increment()
    {
        Interlocked.Increment(ref _counter);
    }
}
Run Code Online (Sandbox Code Playgroud)

对不起,如果我误解了为什么我需要内存屏障?但似乎这表明上述课程在阅读_counter的价值时可能无法提供新鲜度保证.重复访问Counter属性的线程是否会永远停留在旧的Counter值(因为它缓存在寄存器中)?

return _counter;必要之前是内存屏障还是锁?

c# multithreading thread-safety shared-memory memory-barriers

3
推荐指数
1
解决办法
986
查看次数