如何解决C#中跨类多线程共享counter变量的竞态条件问题?
问题分析与解决方案
核心问题
- 主线程
useValue等待工作线程updateValue的信号时,若工作线程未启动或updateValue未执行,会无限阻塞。 updateValue依赖的SomeClassType val无法在useValue所在类访问,导致无法触发工作线程执行更新逻辑。
解决方案思路
- 主动触发工作线程启动,并传递所需参数。
- 给等待操作设置超时,避免主线程无限阻塞。
- 保证跨线程变量的可见性,消除竞态条件。
- 可选:用更现代的异步Task模型替代传统的
AutoResetEvent,简化线程管理。
方案一:完善AutoResetEvent的使用逻辑
工作线程类调整(支持接收参数并启动)
public class WorkerClass { // 用实例级别的事件,避免多实例冲突 private readonly AutoResetEvent _autoResetEvent = new AutoResetEvent(false); // 用volatile保证线程可见性,避免CPU缓存读取旧值 private volatile int _counter = 0; public int Counter => _counter; public AutoResetEvent UpdateCompletedEvent => _autoResetEvent; // 对外提供启动工作线程并执行更新的方法 public void StartUpdate(SomeClassType val) { // 将更新逻辑放到工作线程执行 Thread workerThread = new Thread(() => UpdateValue(val)); workerThread.Start(); } private void UpdateValue(SomeClassType val) { if (val.id) { _counter = 2; } // 发送更新完成信号 _autoResetEvent.Set(); } }
主线程useValue实现
public class MainThreadClass { protected void UseValue() { // 1. 准备工作线程需要的参数实例 SomeClassType val = new SomeClassType(); val.id = true; // 设置触发更新的条件 // 2. 初始化工作类并启动更新线程 WorkerClass worker = new WorkerClass(); worker.StartUpdate(val); // 3. 等待更新完成,设置5秒超时防止无限阻塞 bool isUpdated = worker.UpdateCompletedEvent.WaitOne(TimeSpan.FromSeconds(5)); if (isUpdated) { // 使用更新后的counter执行业务操作 int updatedCounter = worker.Counter; // ... } else { // 处理超时场景,比如日志记录、重试逻辑 // ... } } }
方案二:用Task异步模型(推荐,.NET 4.5+)
无需手动管理线程和事件,异步等待更简洁安全:
public class WorkerClass { private volatile int _counter = 0; public int Counter => _counter; // 异步更新方法,自动放到线程池执行 public async Task UpdateValueAsync(SomeClassType val) { // 模拟耗时操作,替换为实际业务逻辑 await Task.Run(() => { if (val.id) { _counter = 2; } }); } } public class MainThreadClass { // 用async修饰方法,支持await等待更新完成 protected async void UseValue() { SomeClassType val = new SomeClassType { id = true }; WorkerClass worker = new WorkerClass(); // 等待更新完成 await worker.UpdateValueAsync(val); // 直接使用更新后的counter执行业务操作 int updatedCounter = worker.Counter; // ... } }
关键注意点
- 线程可见性:跨线程访问的变量(如
counter)需用volatile修饰,或用Interlocked类操作,避免CPU缓存导致的读取旧值问题。 - 避免静态同步对象:静态
AutoResetEvent会在多实例场景下导致信号混乱,优先用实例级别的同步对象。 - 超时机制:任何线程等待操作都要设置超时,防止主线程无限阻塞影响程序响应。
内容的提问来源于stack exchange,提问作者Nixit Ahir
相关产品推荐
相关产品推荐

