代码之家  ›  专栏  ›  技术社区  ›  Vilx-

.NET:如何确保线程1可以看到线程2在字段中写了什么?

  •  4
  • Vilx-  · 技术社区  · 15 年前

    环境:.NET 3.5 SP1。

    我有两个线程:UI线程和后台工作线程。后台工作线程定期更新共享对象中的某些字段,UI线程检查这些字段。没什么了不起的-只是进度、返回值和抛出的异常。此外,工作线程在UI线程上引发一些事件(通过 Control.BeginInvoke

    工作线程只写入这些字段,UI线程只读取这些字段。它们不用于任何其他通信。为了提高性能,我希望避免锁定共享对象或单个属性。共享对象中永远不会有无效状态。

    然而,我担心处理器缓存和编译器优化之类的事情。如何避免在UI线程的事件处理程序中看不到更新的值的情况?威尔加 volatile

    3 回复  |  直到 15 年前
        1
  •  1
  •   Hans Passant    15 年前

    你没事,不用担心。需要内存屏障来刷新对内存的任何挂起写入。有一个包含任何lock语句的隐式语句。Control.Begin/Invoke()需要使用锁来保护挂起的委托列表,这样就足够了。

        2
  •  0
  •   Stephen Cleary    15 年前

    使用已建立的多线程准则要好得多。 Producer/consumer collections 在.NET 4.0中提供;这些是 适用于.NET 3.5,前提是包含对 Rx library .

    无锁代码几乎不可能正确。如果不想使用生产者/消费者队列,请使用锁。

    如果你坚持走痛苦的道路,那么是的, volatile 将启用读取该变量的任何线程以获取最后写入的值。

        3
  •  0
  •   Brian Gideon    15 年前

    Thread.MemoryBarrier 可以接受。当然,这假设没有原子性要求,共享对象永远不会处于半成品状态。这实际上可能比把所有东西都撒上更容易 volatile .

    object shared;
    
    void WorkerThread()
    {
      MakeChangesToSharedObject(shared);
      Thread.MemoryBarrier(); // commit the changes to main memory
    }
    
    void UIThread()
    {
      Thread.MemoryBarrier(); // ensure updates are read from main memory
      UseSharedObject(shared);
    }
    

    volatile object shared;
    
    void WorkerThread()
    {
      // The following operation is safe because the variable is volatile.
      shared = GetNewSharedObject();
    }
    
    void UIThread()
    {
      // The following operation is safe because the variable is volatile.
      object value = shared.SomeProperty;
    }