使用多线程循环时计数器值没有减少[重复]

问题描述 投票:0回答:1

我正在开发一个多线程应用程序,使用 Task.WhenAll() 来同时处理多个请求。然而,我遇到了意外的行为,共享数据被损坏,可能是由于竞争条件。

代码如下:

public class DataProcessor
{
    private static int _counter = 0;

    public async Task ProcessDataAsync()
    {
        var tasks = new List<Task>();

        for (int i = 0; i < 1000; i++)
        {
            tasks.Add(Task.Run(() => IncrementCounter()));
        }

        await Task.WhenAll(tasks);
    }

    private void IncrementCounter()
    {
        _counter++;
    }
}

运行此代码后,_counter 的值通常小于 1000,这表明可能会丢失一些增量。如何解决此问题并确保多线程上下文中的线程安全操作?

我现在不知道了

c# multithreading async-await thread-safety
1个回答
0
投票

这里的问题是 _counter++ 不是线程安全的。看似简单的增量操作,但实际上涉及三个步骤:

  1. 读取_counter的值。
  2. 增加该值。
  3. 将更新后的值写回_counter。

在多线程环境中,多个线程可以同时读取和递增 _counter,从而导致错过更新和竞争条件。这就是为什么 _counter 的最终值常常小于预期的原因。

使用 Interlocked 进行原子操作:Interlocked 类为跨线程共享的变量提供原子操作。 Interlocked.Increment 确保增量操作是原子的和线程安全的。它避免了竞争条件,无需显式锁定。

互锁类 API - Microsoft

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

public class DataProcessor
{
    // Shared counter, incremented atomically
    private static int _counter = 0;

    public async Task ProcessDataAsync()
    {
        const int taskCount = 1000;
        var tasks = new List<Task>(taskCount);

        // Add tasks to increment the counter
        for (int i = 0; i < taskCount; i++)
        {
            tasks.Add(Task.Run(IncrementCounter));
        }

        // Wait for all tasks to complete
        await Task.WhenAll(tasks);

        Console.WriteLine($"Final Counter Value: {_counter}");
    }

    private void IncrementCounter()
    {
        Interlocked.Increment(ref _counter); // Atomic increment
    }

    // Entry point to test the code
    public static async Task Main(string[] args)
    {
        var processor = new DataProcessor();
        await processor.ProcessDataAsync();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.