Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
379 views
in Technique[技术] by (71.8m points)

atomic - Reproduce torn reads of decimal in c#

Seeing is believing. Can anyone reproduce a program that reads a torn decimal? I tried spinning up multiple threads changing the same decimal between 1 and 2. I did not catch any reads different from 1 or 2.

EDIT: I like to see that a reader thread does not see a atomic change from a writer thread, so the value should be something different from 1 or 2.

void TornDecimalReadTest()
    {
        decimal sharedDecimal = 1;
        int threadCount = 100;
        var threads = new List<Thread>();

        for (int i = 0; i < threadCount; i++)
        {
            int threadId = i;
            var thread = new Thread(() =>
            {
                Thread.Sleep(5000);

                decimal newValue = threadId % 2 == 0 ? 1 : 2;
                bool isWriterThread = threadId % 2 == 0;

                Console.WriteLine("Writer : " + isWriterThread + " - will set value " + newValue);

                for (int j = 0; j < 1000000; j++)
                {
                    if (isWriterThread)
                        sharedDecimal = newValue;

                    decimal decimalRead = sharedDecimal;

                    if (decimalRead != 1 && decimalRead != 2)
                        Console.WriteLine(decimalRead);
                }
            });

            threads.Add(thread);
        }

        threads.ForEach(x => x.Start());
        threads.ForEach(x => x.Join());
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This code will demonstrate a torn read of a Decimal:

using System;
using System.Threading.Tasks;

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

        Decimal d;

        const Decimal VALUE1 = 1m;
        const Decimal VALUE2 = 10000000000m;
    }
}

It happens faster in a release build than a debug build.

I think the reason that you weren't seeing a torn read in your test code is because you were only changing the value between 0 and 1. It's likely that the bits being changed during your test are all in the same word being used to store the value internally, and accesses to words are atomic.

By changing the value between 1 and 10000000000, we force bits to change in two different words, allowing a torn read to be observed.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...