在c#中重现十进制的撕裂读取

时间:2014-04-24 07:27:37

标签: c# atomic lock-free

眼见为实。任何人都可以重现一个读取撕裂小数的程序吗?我尝试旋转多个线程,在1和2之间改变相同的小数。我没有捕获任何与1或2不同的读数。

编辑:我喜欢看到读者线程没有看到来自编写者线程的原子更改,因此该值应该是1或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());
    }

1 个答案:

答案 0 :(得分:3)

此代码将演示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;
    }
}

在发布版本中它比调试版本更快。

我认为您在测试代码中看不到读取错误的原因是因为您只是在0到1之间更改了值。在测试期间更改的位可能是所有在同一个单词中用于在内部存储值,并且对单词的访问是原子的。

通过改变1到10000000000之间的值,我们强制位以两个不同的单词改变,允许观察到撕裂的读数。