【问题标题】:Boolean Property Getter and Setter Locking布尔属性 Getter 和 Setter 锁定
【发布时间】:2011-07-29 13:33:27
【问题描述】:

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

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

【问题讨论】:

  • +1 作为教科书示例

标签: c# multithreading properties locking


【解决方案1】:

好吧,您不一定需要 - 但如果您希望一个线程明确读取另一个线程写入的值,您需要锁或 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

【讨论】:

【解决方案2】:

bool 的读写是atomic

但是,名称“flag”表示单独的线程将读取/写入,直到某些情况发生。为避免由于优化导致的意外行为,您应该考虑在 bool 声明中添加 volatile 关键字。

【讨论】:

  • 原子不一定足够。
【解决方案3】:

没有理由在那儿有锁。

锁定在您的设计中可能很合适,但很怀疑这是正确的粒度。

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

【讨论】:

  • 你怎么知道没有理由锁?我们没有更多的上下文。例如,该标志可能是指示任务“完成”所需的全部 - 虽然有锁的替代方案,但简单地移除锁很可能会导致工作代码中断。有关示例,请参见我的代码。
  • @Jon:您希望锁定整个报告任务结果,而不仅仅是一个属性访问器。 (在任何重要的设计中。)您的示例将锁用作非常昂贵的内存围栏。
  • 是的,但必须有一个一些描述的内存栅栏,而锁是获得该栅栏的一种方式。可能有更好的方法来实现相同的目标,但您的第一句话可能会被解释为“任何带有锁的正确程序在没有锁的情况下也是正确的”——这根本不正确。
  • @Jon:只阅读我回答的第一句话是不明智的。这常常是真的。虽然您已经给出了一个示例,其中属性访问器中的锁提供了所需的内存栅栏,但在可能来自多个线程的 99.9% 的属性访问中,应该在同一个锁下完成一些其他操作,并且在两者之间不释放锁。即使不是这样,在属性访问器中加锁也违反了属性像变量一样起作用的原则。
  • 也许——但也许不是。但鉴于问题是“你有什么理由……”答案是是的。至少在某些情况下,你会这样做的原因。正如我认为您的回答所暗示的那样,这不是绝对毫无意义的代码。
猜你喜欢
  • 2012-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-09
相关资源
最近更新 更多