你有没有理由在这样的布尔属性的getter和setter周围创建锁?
private _lockObject = new object();
private bool _myFlag;
public bool MyFlag
{
get
{
lock (_lockObject)
{
return _myFlag;
}
}
set
{
lock (_lockObject)
{
_myFlag = value;
}
}
}
答案 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)
没有理由在那里锁定。
在您的设计中采取锁定可能是合适的,但是这是正确的粒度非常值得怀疑。
您需要使设计成为线程安全的,而不是单个属性(甚至是整个对象)。