You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#异步操作是否需要加锁?异步多线程竞态问题解析

异步操作中的共享变量竞态问题

问题描述

我编写了一段C#异步代码,预期共享变量a的最终值是50000(5个任务各执行10000次自增),但实际运行结果往往小于等于这个值。一开始误以为异步操作只会在单线程运行,直到添加线程ID打印后,发现任务结束时运行在不同线程,才意识到之前的误解,想知道具体原因。

原始代码

class A
{
    public int a = 0;

    public async Task Test1()
    {
        Console.WriteLine("Test1 START");

        for (long i = 0; i < 10000; ++i)
        {
            a++;
            await Task.Yield();
        }

        Console.WriteLine("Test1 END");
    }
}
class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        Task t1 = a.Test1();
        Console.WriteLine("1");
        Task t2 = a.Test1();
        Console.WriteLine("2");
        Task t3 = a.Test1();
        Console.WriteLine("3");
        Task t4 = a.Test1();
        Console.WriteLine("4");
        Task t5 = a.Test1();
        Console.WriteLine("5");

        while (!t1.IsCompleted || !t2.IsCompleted || !t3.IsCompleted || !t4.IsCompleted || !t5.IsCompleted)
        {
        }
        Console.WriteLine(a.a);

        Console.WriteLine("Main END");
        Console.ReadLine();
    }
}

修改后的代码(添加线程ID打印)

public async Task Test1()
{
    Console.WriteLine("Start Thread ID : " + Thread.CurrentThread.ManagedThreadId);

    for (long i = 0; i < 10000; ++i)
    {
        a++;
        await Task.Yield();
    }

    Console.WriteLine("END Thread ID : " + Thread.CurrentThread.ManagedThreadId);
}

运行结果

Start Thread ID : 1
1
Start Thread ID : 1
2
Start Thread ID : 1
3
Start Thread ID : 1
4
Start Thread ID : 1
5
END Thread ID : 14
END Thread ID : 14
END Thread ID : 5
END Thread ID : 6
END Thread ID : 6
50000
Main END

原因解析

  1. async/await不绑定单线程:控制台程序没有SynchronizationContext,await完成后,后续代码会由线程池调度,可能在任意线程池线程上执行。await Task.Yield()会强制让出当前线程,把后续循环迭代的操作放到线程池队列,所以每个自增操作都可能在不同线程执行。
  2. a++不是原子操作:a++实际包含三个步骤:读取当前a的值、加1、写入新值。当多个线程同时执行这个操作时,会出现竞态条件:比如线程A读取a=10,线程B也读取a=10,两者都加1到11,然后写入,最终a只增加了1,而不是2,这就导致最终结果小于预期的50000。
  3. 空循环等待的偶然性:主函数里的空while循环会占用主线程资源,这次运行结果碰巧是50000只是偶然情况,多次运行大概率会出现值偏小的情况。

内容的提问来源于stack exchange,提问作者박재한

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:23:18