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

如何避免多线程调用函数时的竞态条件?附代码求指导

解决异步代码中的竞态条件问题

原代码的核心问题在于isRunning字段的检查与修改没有同步保护,多线程/异步场景下会出现竞态条件——比如DoSomeOtherTask中判断!isRunning后,还没调用RunThis,另一个线程已经触发MyEvent并将isRunning设为true,导致RunThis被重复执行。

以下是两种可靠的修复方案:

方案一:使用SemaphoreSlim实现异步排他锁

这是异步场景下处理并发最常用的方式,支持非阻塞式等待:

class MyClass
{
    // 初始化信号量,允许1个并发,最大1个并发
    private readonly SemaphoreSlim _executionLock = new SemaphoreSlim(1, 1);

    private async void MyEvent() // EventHandler
    {
        await RunThis();
    }

    private async Task RunThis()
    {
        await _executionLock.WaitAsync();
        try
        {
            // 执行你的异步操作
            // Do Some Async Stuff
        }
        finally
        {
            // 无论是否异常,都释放信号量
            _executionLock.Release();
        }
    }

    public Task DoSomeOtherTask()
    {
        _ = Task.Run(async () =>
        {
            await RunThis();
        });

        return SomeOtherTask();
    }
}

方案二:保留"仅当未运行时才执行"的逻辑

如果需要判断当前是否在运行,避免等待直接跳过,可以用WaitAsync(0)尝试非阻塞获取锁:

class MyClass
{
    private readonly SemaphoreSlim _executionLock = new SemaphoreSlim(1, 1);

    private async void MyEvent() // EventHandler
    {
        await RunThis();
    }

    private async Task RunThis()
    {
        await _executionLock.WaitAsync();
        try
        {
            // Do Some Async Stuff
        }
        finally
        {
            _executionLock.Release();
        }
    }

    public Task DoSomeOtherTask()
    {
        _ = Task.Run(async () =>
        {
            // 尝试立即获取锁,获取成功才执行
            if (_executionLock.WaitAsync(TimeSpan.Zero).IsCompletedSuccessfully)
            {
                try
                {
                    // Do Some Async Stuff
                }
                finally
                {
                    _executionLock.Release();
                }
            }
        });

        return SomeOtherTask();
    }
}

关键说明

  • 不要用普通bool字段做并发控制:普通bool的读写不是原子操作,且检查+执行的组合无法保证原子性。
  • 避免用lock关键字:lock是同步锁,会阻塞线程,不适合异步方法中使用,而SemaphoreSlim支持异步等待,不会浪费线程资源。

内容的提问来源于stack exchange,提问作者ledragon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 03:23:15