2

Another answer regarding reproducing torn thread reads of decimal values in c# shows that this code successfully does reproduce a torn thread. I am able to successfully reproduce that behavior in my environment as well. However, if I change Decimal d; to public static Decimal d { get; set; } the torn thread is not reproduced. Why is that?

Separately, I am using a series of lock statements to prevent torn threads. The only way I will feel comfortable that I have permanently prevented torn threads is to be able to generate torn threads on purpose, apply lock statements in the same method I am using in production bound code, and see that the locks successfully do what they are supposed to without significant performance impact. Is there a better way to purposefully generate torn threads?

If changing to public static is enough to cause a timing difference in my environment, then I'm fearful that lock statements could be causing the same timing differences as well rather than actually locking what I'm intending to be locked. Is there a way to create a better test rig?

Edit: My environment is - Target Framework netcoreapp2.0, Windows 10 64-bit, Intel Core i7-4712HQ. Using different Platform targets of Any, x86, or x64 does not impact the test results in my environment. Neither does building with or without "Optimize code" enabled.

using System;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        void run()
        {
            Task.Run((Action)setter);
            Task.Run((Action)checker);

            Console.WriteLine("Press <ENTER> to stop");
            Console.ReadLine();
        }

        void setter()
        {
            while (true)
            {
                d = VALUE1;
                d = VALUE2;
            }
        }

        void checker()
        {
            for (int count = 0; ; ++count)
            {
                var t = d;

                if (t != VALUE1 && t != VALUE2)
                    Console.WriteLine("Value is torn after {0} iterations: {1}", count, t);
            }
        }

        static void Main()
        {
            new Program().run();
        }

        //Torn thread is not reproduced if this line changed to:
        //public static Decimal d { get; set; }
        Decimal d;

        const Decimal VALUE1 = 1m;
        const Decimal VALUE2 = 10000000000m;
    }
}
user963263
  • 453
  • 1
  • 3
  • 14
  • 3
    If I compile the code with optimizations, it tears on my machine whether or not the field is `static`. If I don't compile it with optimizations, it won't tear at all. The exact conditions would vary with your processor and the JIT being used, I'd wager. That it *can* tear doesn't mean there's a guaranteed way to get it to tear. Specifically, if you change it to a static *property*, like you did, the JIT isn't required to optimize this to direct field access, and the method call can throw off the timing. – Jeroen Mostert Oct 29 '17 at 16:37
  • @JeroenMostert Thanks for those details. Following your comment, I attempted to compile with and without optimizations with no impact to my test results. I have updated my question with that detail along with other details about my environment. – user963263 Oct 29 '17 at 17:22
  • 2
    You can only observe tearing if the Decimal value crosses a cache line boundary. The poster of that answer just got lucky, the odds are not actually that great. I think only 3 out of 16 in x86 code, give or take. Having no direct control over variable placement is implicit in managed code. You can play with [this code](https://stackoverflow.com/a/9054170/17034). – Hans Passant Oct 31 '17 at 14:29
  • @HansPassant Thanks for the suggestion. If I try the code you linked to in your other answer, it does not tear for me in 64 bit, but if I change to 32 bit it crashes with the message "dotnet has stopped working". – user963263 Nov 01 '17 at 02:17

0 Answers0