Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 对布尔值使用Interlocked.CompareExchange()操作?_C#_Multithreading - Fatal编程技术网

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

我有两个问题:

  • 是否需要使用联锁类来访问布尔值?默认情况下,对布尔值的读取或写入不是原子的吗

  • 我尝试在布尔值上使用Interlocked.CompareeExchange,但出现以下错误:

    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
    方法确保线程安全。这是一个稍微慢一点的解决方案,但根据您的性能要求,这可能仍然是首选方法

  • 滚动您自己的“AtomicBoolean”类(该类将
    包装为互锁的。比较交换(…)


    测试用例(如果要在生产中使用它):

    您可以在
    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                
    }