Is this an atomic surrogate "Int64"?

I am going to create a "long" (Int64) surrogate, which should be atomic, so a copy of it in a parallel application will be inherently safe. I cannot use Int32 because it is too short as a range.

I know that atomicity should be a guarantee, since the data involved can fit into a double word (32 bits). Regardless of whether the OS is 32 or 64 bit.

Now consider the following "long" surrogate ...

NOTE. I omitted several methods because I do not need them. In this case, I only need a basic conversion to / from the real one.

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 } 

Well, it looks like it is working fine, as I expect.

Here is a little test:

 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(); } } 

The SizeOf function always gives 4 bytes as the size of my surrogate. Does this value mean atomicity of the SafeLong-to-SafeLong copy, or should 4 bytes be interpreted as a "real physical double word"?

Regardless of the atomicity of the long ↔ SafeLong: it will be enclosed in a safe context.

Thank you very much in advance.

+6
source share
1 answer

You are right that it is atomic, but holy kindness is a complex solution to a simple problem. If you want the structure to be long, but use links for atomic, just enter long! In fact, if you do this, you can make an atomic version of any type of structure, so let it do:

 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); } } 

And you're done. Why are you doing all this with an array?

In addition, I note that in your implementation, you got explicit / implicit conversions back. A transformation must be implicit if it is lossless and does not drop. Your implicit conversion from SafeLong to long can throw, so it should not be implicit. Your explicit conversion from long to SafeLong cannot be lossless, so it can be implicit if you wanted to. As you can see, I solved the problem in my implementation by making both directions lossless and not throwing, so they are both implicit.

Note that this structure is essentially a strongly typed wrapper around the value in the box; if generic types were available in the first version of the CLR, then, of course, types with short values ​​would be implemented using a type like this, just as null value types are similarly implemented by a special generic type.

The SizeOf function always gives 4 bytes as the size of my surrogate. Does this value mean atomicity of a SafeLong-to-SafeLong copy?

Good, yes and no.

First, the "SizeOf" method does not give the size of the structure in memory; it gives the size of the structure when it is stored on a managed / unmanaged border. This does not necessarily match the size of the structure in managed memory; this is often the same, but it is not guaranteed that it will be the same. If you want to know the size of the structure in managed memory, you need to enable "unsafe" mode and use the "sizeof" operator.

Typically, a copy of a structure of size 4 will always be atomic if it is copied to a location aligned on the border of four bytes. The language specification does not guarantee that any four-byte structure will be copied atomically, although this is actually true in our implementation.

In your particular case, these four bytes are an array reference; the language specification ensures that the link is always copied atomically.

+13
source

Source: https://habr.com/ru/post/892687/


All Articles