c#之不能通过并发线程访问破坏数据

exmyth 阅读:63 2025-06-02 22:19:02 评论:0

我写这个实验是为了向某人证明使用多个线程同时访问共享数据是一个很大的禁忌。令我惊讶的是,无论我创建了多少线程,我都无法创建并发问题并且该值始终导致平衡值 0。我知道增量运算符不是线程安全的,这就是为什么有方法像 Interlocked.Increment()Interlocked.Decrement() (也在这里注明 Is the ++ operator thread safe? )。

如果递增/递减运算符不是线程安全的,那么为什么下面的代码执行没有任何问题并且结果达到预期值?

下面的代码片段创建了 2,000 个线程。 1,000 不断递增,1,000 不断递减,以确保多个线程同时访问数据。更糟糕的是,在普通程序中,您不会有那么多线程。然而,尽管为了创建并发问题而夸大了数字,但该值始终导致平衡值 0。

static void Main(string[] args) 
    { 
        Random random = new Random(); 
        int value = 0; 
 
        for (int x=0; x<1000; x++) 
        { 
            Thread incThread = new Thread(() => 
            { 
                for (int y=0; y<100; y++) 
                { 
                    Console.WriteLine("Incrementing"); 
                    value++; 
                } 
            }); 
 
            Thread decThread = new Thread(() => 
            { 
                for (int z=0; z<100; z++) 
                { 
                    Console.WriteLine("Decrementing"); 
                    value--; 
                } 
            }); 
 
            incThread.Start(); 
            decThread.Start(); 
        } 
 
        Thread.Sleep(TimeSpan.FromSeconds(15)); 
        Console.WriteLine(value); 
        Console.ReadLine(); 
    } 

我希望有人能给我一个解释,这样我就知道我为编写线程安全软件所做的所有努力都没有白费,或者这个实验可能在某些方面存在缺陷。我还尝试了所有线程递增并使用++i 而不是 i++。该值始终会产生预期值。

请您参考如下方法:

如果您有两个在非常 接近的时间递增和递减的线程,您通常只会看到问题。 (也有内存模型问题,但它们是分开的。)这意味着您希望它们花费大部分时间递增和递减,以便为您提供操作冲突的最佳机会。

目前,您的线程将花费大量 大部分时间休眠或写入控制台。这大大降低了碰撞的可能性。

此外,我要指出的是,没有证据并不代表没有证据——并发问题确实很难引发,尤其是当你碰巧运行在具有强大内存模型和内部原子递增/递减的 CPU 上时JIT 可以使用的指令。可能是您永远不会在您的特定机器上引发问题 - 但同一程序可能会在另一台机器上失败。


标签:C#
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号