如何避免多线程调用函数时的竞态条件?附代码求指导
解决异步代码中的竞态条件问题
原代码的核心问题在于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
相关产品推荐
相关产品推荐

