线程安全-在C#中再现损坏的十进制读数



眼见为实。有人能复制一个读破小数的程序吗?我尝试旋转多个线程,在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());
}

此代码将演示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之间更改值,我们强制位在两个不同的字中更改,从而可以观察到撕裂的读取。

相关内容

  • 没有找到相关文章

最新更新