Strange behavior with volatile write on class member vs struct member

I am developing a component that needs a long type with mutable semantics.
Since .NET does not have volatile long , I created a simple wrapper type that handles read / write access using the Volatile class.
I did not know if I should go with a class or structure, so I decided to check both of them, and I came across very strange behavior.

Here's the test code:

 internal class Program { private class VolatileLongClass { private long value; public long Value { get { return Volatile.Read(ref value); } set { Volatile.Write(ref this.value, value); } } } private struct VolatileLongStruct { private long value; public long Value { get { return Volatile.Read(ref value); } set { Volatile.Write(ref this.value, value); } } } private static void Main() { const int iterations = 10; var totalTime = 0L; for (var i = 0; i < iterations; i++) { var watch = Stopwatch.StartNew(); var volatileLong = new VolatileLongClass(); //<-- change to VolatileLongStruct for (var j = 0L; j < 10 * 1000 * 1000; j++) volatileLong.Value = j; var msElapsed = watch.ElapsedMilliseconds; Console.Out.WriteLine("Ms Elapsed = {0}", msElapsed); totalTime += msElapsed; } Console.Out.WriteLine("Avg = {0:N2}", (double) totalTime / iterations); } } 

The output I get for VolatileLongStruct:

 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Avg = 109.00 

The above conclusion for the structure is consistent. However, the output for VolatileLongClass is:

 Ms Elapsed = 17558 <-- *** Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 17541 <-- *** Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Avg = 3,593.90 

As you can see, there is a significant time difference for some iterations. The exact iteration (s) that takes an abnormal time varies a bit, but there is a constant problem with at least one of the iterations.

Can someone shed some light on the question, why would volatile write take (sometimes) more on a class member than on a structure member?

By the way, the above result was obtained using .Net 4.5 and Release build

+4
source share
1 answer

The time difference is most likely the result of var volatileLong = new VolatileLongClass(); inside the loop; this statement forces the compiler to allocate once a place to store the VolatileLongClass link, and then at each pass through the loop create a new object and save the link in this place. In contrast, the operator var volatileLong = new VolatileLongStruct(); makes the compiler - once - allocate storage space for the VolatileLongStruct instance, and then each time it passes through the loop, mutate the existing instance by zeroing all its data (using regular, not volatile, writes).

Note that if the code requires that the structs fields have certain multithreaded semantics, such fields should often be published, and the structure should be considered as a group of variables glued together with adhesive tape (for example, public struct IntPair {public int V1,V2;} IntPair myPair; should be regarded as the establishment of two separate variables myPair.V1 and myPair.V2 ] since the structure in fact is a combination of variables, glued together with an adhesive tape, and as any other abstraction represented by structure softening. wherein p is not equal to 1, 2 or 4 bytes to be "leaky", especially with respect to multi-threaded behavior is better that the structure represented itself what it is, and not claim that it is not.

+1
source

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


All Articles