C# 对布尔值使用Interlocked.CompareExchange()操作?
我有两个问题:C# 对布尔值使用Interlocked.CompareExchange()操作?,c#,multithreading,C#,Multithreading,我有两个问题: 是否需要使用联锁类来访问布尔值?默认情况下,对布尔值的读取或写入不是原子的吗 我尝试在布尔值上使用Interlocked.CompareeExchange,但出现以下错误: bool value = true; Interlocked.CompareExchange<bool>(ref value, false, true); bool值=真; 联锁。比较交换(参考值,假,真); 错误:类型“bool”必须是引用类型,才能将其用作泛型类型或方法“System.Th
bool value = true;
Interlocked.CompareExchange<bool>(ref value, false, true);
bool值=真;
联锁。比较交换(参考值,假,真);
错误:类型“bool”必须是引用类型,才能将其用作泛型类型或方法“System.Threading.Interlocated.CompareExchange(ref T,T,T)”中的参数“T”我该如何解决这个问题?您不能使用interlocked for Boolean。你最好用int来代替
Interlocked
类使整个事务原子化公共静态T比较交换(ref T a,T b,T c)),其中T:class
重载只能与引用类型一起使用(请注意末尾的where T:class
子句)。您可以使用compareeexchange(Int32,Int32,Int32)
重载代替布尔值,并使用Int32
切换布尔值
或者,如果希望保留布尔类型的变量,可以使用lock
方法确保线程安全。这是一个稍微慢一点的解决方案,但根据您的性能要求,这可能仍然是首选方法包装为互锁的。比较交换(…)
)
测试用例(如果要在生产中使用它): 您可以在
int
上使用:
int boolValue = 0;
// ...
if (System.Threading.Interlocked.Exchange(ref boolValue, 1) == 1)
{
// Was True
}
else
{
// Was False
}
你的问题没有提到神奇的“线程”这个词。你想做什么?这似乎有点太复杂了。让一个带有单个静态实例的
AtomicBoolean
类Truth
,并将对Truth
的任何引用解释为true,将任何其他引用解释为false,怎么样?@supercat更新为包含一个我将如何使用它的示例;我认为用例并不太复杂。我想要的是一个带有原子操作的布尔包装器。我认为您的建议可能会更好地用于枚举——可能是作为有限状态机的一部分(状态之间的更改需要是原子的)。我的观点是,如果您将AtomicBoolean
定义为一个没有公共构造函数但在bool
(其中,true
是对将永远存在的唯一实例的引用,false
为空)框架中的互锁
方法将按照预期的语义工作。类型为AtomicBoolean
的每个变量将封装一个原子布尔
状态,因此除了缺少公共构造函数外,其行为类似于类型为Bool
的变量。如果AtomicBool
在teger,每个变量将封装的不是原子状态,而是……一个对象的标识,该对象具有原子布尔状态;如果两个变量具有对同一实例的引用,则对其中一个变量执行的原子操作将影响两个变量报告的状态(因为两个变量都将报告同一实例的状态).一条评论(一年半后):据我所知,在.NET内存模型中,您需要在值设置程序中使用联锁.Exchange
,否则其他线程不能保证立即看到写入的值。或者,您可以将zeroOrOne
标记为volatile
。
class MultithreadedClass
{
private AtomicBoolean isUpdating = new AtomicBoolean(false);
public void Update()
{
if (!this.isUpdating.FalseToTrue())
{
return; //a different thread is already updating
}
try
{
//... do update.
}
finally
{
this.isUpdating.Value = false; //we are done updating
}
}
}
[TestClass]
public class AtomicBooleanTest
{
[TestMethod]
public void TestAtomicBoolean()
{
AtomicBoolean b = new AtomicBoolean();
Assert.IsFalse(b.Value);
b = new AtomicBoolean(false);
Assert.IsFalse(b.Value);
b = new AtomicBoolean(true);
Assert.IsTrue(b.Value);
//when Value is already true, FalseToTrue fails
b.Value = true;
Assert.IsFalse(b.FalseToTrue());
Assert.IsTrue(b.Value);
//when Value is already false, TrueToFalse fails
b.Value = false;
Assert.IsFalse(b.TrueToFalse());
Assert.IsFalse(b.Value);
//Value not changed if SetWhen fails
b.Value = false;
Assert.IsFalse(b.SetWhen(true, true));
Assert.IsFalse(b.Value);
//Value not changed if SetWhen fails
b.Value = true;
Assert.IsFalse(b.SetWhen(false, false));
Assert.IsTrue(b.Value);
}
}
int boolValue = 0;
// ...
if (System.Threading.Interlocked.Exchange(ref boolValue, 1) == 1)
{
// Was True
}
else
{
// Was False
}