为什么以下 C# 多线程代码在调试器中输出零但不输出零?

发布于 2024-10-26 02:59:49 字数 783 浏览 2 评论 0原文

class Program
{
    private static volatile int value;

    public static void Increment()
    {
        for (int i =0; i <100000; i++)
        {
            value++;
        }
    }

    public static void Decrement()
    {
        for (int j =0 ; j < 100000; j++)
        {
            value--;
        }
    }

    public static void ThreadTest()
    {
        value = 0;

        var incrementThread = new Thread(Increment);

        var decrementThread = new Thread(Decrement);

        incrementThread.Start();

        decrementThread.Start();

        incrementThread.Join();

        decrementThread.Join();

        Console.WriteLine("Value of value {0}", value);
    }

    static void Main(string[] args)
    {
        ThreadTest();
    }
}
class Program
{
    private static volatile int value;

    public static void Increment()
    {
        for (int i =0; i <100000; i++)
        {
            value++;
        }
    }

    public static void Decrement()
    {
        for (int j =0 ; j < 100000; j++)
        {
            value--;
        }
    }

    public static void ThreadTest()
    {
        value = 0;

        var incrementThread = new Thread(Increment);

        var decrementThread = new Thread(Decrement);

        incrementThread.Start();

        decrementThread.Start();

        incrementThread.Join();

        decrementThread.Join();

        Console.WriteLine("Value of value {0}", value);
    }

    static void Main(string[] args)
    {
        ThreadTest();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

病毒体 2024-11-02 02:59:49

因为它不应该... ++ 和 -- 不是原子操作(与 Interlocked.XXXX 操作 - Interlocked.Increment 不同)。

如果你写下 ++ 和 -- 的每个步骤,看看两者如何被不同的线程混合,你就会明白为什么:

递增

1: load value to temp
2: add temp, 1
3: store temp to value

递减

4: load value to temp2
5: substruct temp2, 1
6: store temp2 to value

因此,如果顺序是 1,2,3,4,5,6,你会得到 value = 0 ;但如果顺序是 1,2,4,5,6,3,则值 = 1。

Because it is not supposed to... ++ and -- are not atomic operations (unlike Interlocked.XXXX opreations - Interlocked.Increment).

If you write down each step of ++ and -- and see how both can be intermixed by different threads you'll see why:

increment

1: load value to temp
2: add temp, 1
3: store temp to value

decrement

4: load value to temp2
5: substruct temp2, 1
6: store temp2 to value

So if order is 1,2,3,4,5,6 you get value = 0; but if order is 1,2,4,5,6,3 you get value = 1.

温折酒 2024-11-02 02:59:49

只是想让事情变得更简单......我当天也解决了这个问题:D

Volatile 确保您读取最新值,并且当您写入所有线程时看到新值(这就是易失性操作的用途) ,但它不能确保在读取和写入之间,其他线程不会修改该值。另一方面,Interlocked(提供原子操作)确实确保了这一点。

例如,当一个或多个线程读取和其他修改时,易失性操作是好的。例如,如果您的类中有一个易失性布尔_dispose标志,那么如果一个线程处置它,它会立即被标记为所有线程的处置。

Only trying to make the things simpler... I fought this issue back in the day as well :D

Volatile ensure you read the latest value, and when you write all threads see that new value (and that is what volatile operations are for), but it doesn't ensure that between the read and the write, other thread is not going to modify the value. In the other hand, Interlocked (that provides atomic operations) does ensure it.

Volatile operations are good, when for example a thread or threads read and other modify. For example if you have a volatile Boolean _disposed flag in your class, so if one thread dispose it, it's marked as disposed for all threads straight away.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文