簡體   English   中英

對布爾值使用 Interlocked.CompareExchange() 操作?

[英]Using Interlocked.CompareExchange() operation on a bool value?

我有兩個問題:

  1. 是否需要使用聯鎖 class 來訪問 boolean 值? 默認情況下,對 boolean 值的讀取或寫入不是原子的嗎?

  2. 我嘗試在 boolean 上使用 Interlocked.CompareExchange 並收到以下錯誤:

     bool value = true; Interlocked.CompareExchange<bool>(ref value, false, true);

    錯誤:類型“bool”必須是引用類型才能將其用作泛型類型或方法“System.Threading.Interlocked.CompareExchange(ref T, T, T)”中的參數“T”

我如何解決這個問題?

  1. 分別讀取或寫入 boolean 值原子的,但“比較和交換”對同一地址進行讀取和寫入,這意味着整個事務不是原子的。 如果多個線程可以寫入同一位置,則需要使用Interlocked class 使整個事務原子化。

  2. public static T CompareExchange<T>(ref T a, T b, T c)) where T: class重載只能與引用類型一起使用(注意結尾處的where T: class )。 您可以使用CompareExchange(Int32, Int32, Int32)重載,並將 boolean 與Int32切換,而不是 boolean 值。

    或者,如果要保留 boolean 類型的變量,可以使用lock方法來確保線程安全。 這將是一個稍慢的解決方案,但根據您的性能要求,這可能仍然是首選方式。

滾動您自己的“AtomicBoolean” class (包裝Interlocked.CompareExchange(...)

using System.Threading;

public class AtomicBoolean
{
    private const int TRUE_VALUE = 1;
    private const int FALSE_VALUE = 0;
    private int zeroOrOne = FALSE_VALUE;

    public AtomicBoolean()
        : this(false)
    { }

    public AtomicBoolean(bool initialValue)
    {
        this.Value = initialValue;
    }

    /// <summary>
    /// Provides (non-thread-safe) access to the backing value
    /// </summary>
    public bool Value
    {
        get
        {
            return zeroOrOne == TRUE_VALUE;
        }
        set
        {
            zeroOrOne = (value ? TRUE_VALUE : FALSE_VALUE);
        }
    }

    /// <summary>
    /// Attempt changing the backing value from true to false.
    /// </summary>
    /// <returns>Whether the value was (atomically) changed from false to true.</returns>
    public bool FalseToTrue()
    {
        return SetWhen(true, false);
    }

    /// <summary>
    /// Attempt changing the backing value from false to true.
    /// </summary>
    /// <returns>Whether the value was (atomically) changed from true to false.</returns>
    public bool TrueToFalse()
    {
        return SetWhen(false, true);
    }

    /// <summary>
    /// Attempt changing from "whenValue" to "setToValue".
    /// Fails if this.Value is not "whenValue".
    /// </summary>
    /// <param name="setToValue"></param>
    /// <param name="whenValue"></param>
    /// <returns></returns>
    public bool SetWhen(bool setToValue, bool whenValue)
    {
        int comparand = whenValue ? TRUE_VALUE : FALSE_VALUE;
        int result = Interlocked.CompareExchange(ref zeroOrOne, (setToValue ? TRUE_VALUE : FALSE_VALUE), comparand);
        bool originalValue = result == TRUE_VALUE;
        return originalValue == whenValue;
    }
}

示例用法

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上使用Interlocked.Exchange

int boolValue = 0;

// ...

if (System.Threading.Interlocked.Exchange(ref boolValue, 1) == 1)
{
    // Was True
}
else
{
    // Was False                
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM