在C#中重现十进制的残缺读取 [英] Reproduce torn reads of decimal in c#

查看:84
本文介绍了在C#中重现十进制的残缺读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

眼见为实.任何人都可以重现读取小数位残缺的程序吗?我尝试旋转多个线程以在1和2之间更改相同的十进制数.我没有捕获到与1或2不同的任何读数.

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.

我希望看到读取器线程看不到写入器线程的原子变化,因此该值应与1或2不同.

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

推荐答案

此代码将演示对Decimal的读取破损的内容:

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.

我认为您未在测试代码中看到读取被撕裂的原因是因为您仅在0到1之间更改了值.测试期间更改的位可能都在同一个字中用于内部存储值,并且对单词的访问是原子的.

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.

通过在1到10000000000之间改变值,我们迫使位改变两个不同的字,从而观察到读取结果被撕裂.

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

这篇关于在C#中重现十进制的残缺读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆