簡體   English   中英

這個“Int64”代理是原子的嗎?

[英]Is it atomic this “Int64” surrogate?

我將創建一個必須是原子的“長”(Int64)代理,因此它在並發應用程序中的副本本質上是安全的。 我不能使用 Int32,因為它的范圍太短。

我知道只要涉及的數據可以放在雙字(32位)中,就應該保證原子性。 無論操作系統是 32 位還是 64 位。

現在,考慮以下“長”代理...

注意:我省略了幾種方法,因為我不需要它們。 在這種情況下,我只需要到/從真正的 long 的基本轉換。

public struct SafeLong
    : IConvertible
{
    public SafeLong(long value)
    {
        unchecked
        {
            var arg = (ulong)value;
            this._data = new byte[]
            {
                (byte)arg,
                (byte)(arg >> 8),
                (byte)(arg >> 16),
                (byte)(arg >> 24),
                (byte)(arg >> 32),
                (byte)(arg >> 40),
                (byte)(arg >> 48),
                (byte)(arg >> 56),
            };
        }
    }



    private byte[] _data;



    private long Value
    {
        get
        {
            unchecked
            {
                var lo =
                    this._data[0] |
                    this._data[1] << 8 |
                    this._data[2] << 16 |
                    this._data[3] << 24;

                var hi = 
                    this._data[4] |
                    this._data[5] << 8 |
                    this._data[6] << 16 |
                    this._data[7] << 24;

                return (long)((uint)lo | (ulong)(uint)hi << 32);
            }
        }
    }



    public static implicit operator long(SafeLong value)
    {
        return value.Value;  // implicit conversion
    }



    public static explicit operator SafeLong(long value)
    {
        return new SafeLong(value);  // explicit conversion
    }


    #region IConvertible implementation

    public TypeCode GetTypeCode()
    {
        return Type.GetTypeCode(typeof(SafeLong));
    }

    public object ToType(Type conversionType, IFormatProvider provider)
    {
        return Convert.ChangeType(this.Value, conversionType);
    }

    public long ToInt64(IFormatProvider provider)
    {
        return this.Value;
    }

    // ... OMISSIS (not implemented) ...

    #endregion
}

好吧,它似乎像我預期的那樣完美地工作。

這是一個小測試:

class Program
{
    static void Main(string[] args)
    {
        var sla = (SafeLong)12345678987654321L;
        var la = (long)sla;
        Console.WriteLine(la);

        var slb = (SafeLong)(-998877665544332211L);
        var lb = (long)slb;
        Console.WriteLine(lb);

        Console.WriteLine(Marshal.SizeOf(typeof(SafeLong)));
        Console.WriteLine(Marshal.SizeOf(sla));
        Console.WriteLine(Marshal.SizeOf(slb));

        long lc = new SafeLong(556677);
        var slc = slb;
        Console.WriteLine(slc);
        slc = (SafeLong)lc;
        Console.WriteLine(slc);
        Console.WriteLine(slb);

        Console.Write("Press any key...");
        Console.ReadKey();
    }
}

SizeOf function 總是產生 4 個字節作為我的代理的大小。 這個值是否保證了 SafeLong-to-SafeLong 副本的原子性,或者這 4 個字節應該被解釋為“真正的物理雙字”?

無論 long <--> SafeLong: 的非原子性如何:它將被包含在一個安全的上下文中。

提前非常感謝。

你是對的,這是原子性的,但神聖的善良是一個簡單問題的復雜解決方案。 如果你想要一個具有 long 值但使用原子引用的結構,只需將 long 裝箱,事實上,如果你這樣做,那么你可以制作任何結構類型的原子版本:所以讓我們這樣做:

public struct SafeThing<T> where T : struct
{
    private object boxedThing;

    public SafeThing(T value)
    {
        boxedThing = value;
    }

    public T Value { get { return boxedThing == null ? default(T) : (T)boxedThing; } }

    public static implicit operator T(SafeThing<T> value)
    {
        return value.Value; 
    }

    public static implicit operator SafeThing<T>(T value)
    {
        return new SafeThing(value); 
    }
}

你完成了。 你為什么要在數組中亂七八糟?

另外,我注意到在您的實現中,您已經向后進行了顯式/隱式轉換。 只有在無損且不拋出時,轉換才應該是隱式的。 您從 SafeLong 到 long 的隱式轉換可能會拋出,因此它不應該是隱式的。 您從 long 到 SafeLong 的顯式轉換不能拋出並且是無損的,因此如果您希望它可以是隱式的。 正如你所看到的,我通過使兩個方向都無損和不拋出來解決了我的實現中的問題,所以它們都是隱式的。

請注意,這個結構本質上是一個圍繞裝箱值的強類型包裝器; 如果泛型類型在 CLR 的第一個版本中可用,那么毫無疑問,裝箱值類型將使用類似這樣的某種類型來實現,就像可空值類型類似地由特殊泛型類型實現一樣。

SizeOf function 總是產生 4 個字節作為我的代理的大小。 這個值是否保證了 SafeLong-to-SafeLong 副本的原子性?

嗯,是的,也不是。

首先,“SizeOf”方法沒有給出 memory 中結構的大小; 當它跨越托管/非托管邊界時,它給出了結構的大小。 這不一定與托管 memory 中結構的大小相同; 通常是相同的,但不能保證相同。 如果您想知道托管 memory 中結構的大小,則需要打開“不安全”模式並使用“sizeof”運算符。

實際上,大小為 4 的結構的副本始終是原子的,前提是它被復制到與四字節邊界對齊的位置。 語言規范不保證任何四字節結構都會被原子復制,盡管事實上在我們的實現中是這樣的。

在您的特定情況下,這四個字節是對數組的引用; 語言規范確實保證始終以原子方式復制引用。

暫無
暫無

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

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