布尔属性Getter和Setter锁定

时间:2011-07-29 13:33:28

标签: c# multithreading properties locking

你有没有理由在这样的布尔属性的getter和setter周围创建锁?

  private _lockObject = new object();
  private bool _myFlag;
  public bool MyFlag
  {
    get
    {
      lock (_lockObject)
      {
        return _myFlag;
      }
    }
    set
    {
      lock (_lockObject)
      {
        _myFlag = value;
      }
    }
  }

3 个答案:

答案 0 :(得分:24)

嗯,你不一定需要 locks - 但如果你想让一个线程肯定读取另一个线程写的值,你需要锁或一个volatile变量。

我个人放弃了试图理解volatile的确切含义。我尽量避免编写自己的无锁代码,而是依赖真正了解内存模型的专家。

编辑:作为这可能导致的问题的一个例子,请考虑以下代码:

using System;
using System.Threading;

public class Test
{
    private static bool stop = false;

    private bool Stop
    {
        get { return stop; }
        set { stop = value; }
    }

    private static void Main()
    {
        Thread t = new Thread(DoWork);
        t.Start();
        Thread.Sleep(1000); // Let it get started
        Console.WriteLine("Setting stop flag");
        Stop = true;
        Console.WriteLine("Set");
        t.Join();
    }

    private static void DoWork()
    {
        Console.WriteLine("Tight looping...");
        while (!Stop)
        {
        }
        Console.WriteLine("Done.");
    }
}

该程序可能会或可能不会终止。我看到两者都发生了。无法保证“读取”线程实际上从主存储器中读取 - 它可以将stop的初始值放入寄存器中,并且永远使用它。实际上,我已经看到了这种情况。它不会发生在我当前的机器上,但它可能会在我的下一台机器上发生。

根据问题中的代码将锁置于属性getter / setter中将使此代码正确并且其行为可预测。

有关详情,请参阅此blog post by Eric Lippert

答案 1 :(得分:1)

bool的读写是atomic

但名称"标志"表示在发生某些情况之前,单独的线程将进行读/写。为避免因优化而出现意外行为,您应考虑将volatile关键字添加到bool声明中。

答案 2 :(得分:-3)

没有理由在那里锁定。

在您的设计中采取锁定可能是合适的,但是这是正确的粒度非常值得怀疑。

您需要使设计成为线程安全的,而不是单个属性(甚至是整个对象)。