使用Task时lock与monitor无法解决竞态条件问题咨询
问题:Task同步Counter时竞态条件未解决
我定义了一个Counter,理论上最终值应该是0——因为有一个递增方法和一个递减方法,各执行1000次。用Thread处理时没问题,但用Task时出现了竞态条件。我尝试用lock和monitor做同步,但问题依旧,结果和没加同步机制时一样。
相关代码如下:
namespace ConsoleApp1 { public class LockDemo { private readonly static object _lock = new object(); private static int _count = 0; public void Main() { var tasks = new List<Task>(); for (int i = 0; i < 1000; i++) { tasks.Add(new Task(() => IncrementCounter())); tasks.Add(new Task(() => DecrementCounter())); } foreach (var item in tasks) { item.Start(); } } void IncrementCounter() { Console.WriteLine("wait for opening lock..."); lock (_lock) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("enter the critical section"); _count += 1; Console.WriteLine("Counter:" + _count); Console.ForegroundColor = ConsoleColor.White; } Console.WriteLine("exit critical section"); } void DecrementCounter() { Console.WriteLine("wait for opening lock..."); lock (_lock) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("enter the critical section"); _count -= 1; Console.WriteLine("Counter:" + _count); Console.ForegroundColor = ConsoleColor.White; } Console.WriteLine("exit critical section"); } } }
问题原因
lock本身的同步逻辑是有效的,能保证临界区操作的原子性。真正的问题是主线程没有等待所有Task执行完毕:你创建并启动了2000个Task,但Main方法会直接结束,进程可能在所有Task执行完成前就终止,导致最终看到的_count值不是预期的0。
修复方案
在启动所有Task后,添加等待逻辑,确保所有任务完成后再结束程序,同时输出最终的计数结果:
修复后的代码示例:
namespace ConsoleApp1 { public class LockDemo { private readonly static object _lock = new object(); private static int _count = 0; public void Main() { var tasks = new List<Task>(); for (int i = 0; i < 1000; i++) { tasks.Add(new Task(() => IncrementCounter())); tasks.Add(new Task(() => DecrementCounter())); } foreach (var item in tasks) { item.Start(); } // 等待所有Task执行完成 Task.WaitAll(tasks.ToArray()); // 输出最终计数 Console.WriteLine($"最终Counter值: {_count}"); } void IncrementCounter() { lock (_lock) { Console.ForegroundColor = ConsoleColor.Green; _count += 1; Console.WriteLine($"递增后Counter: {_count}"); Console.ForegroundColor = ConsoleColor.White; } } void DecrementCounter() { lock (_lock) { Console.ForegroundColor = ConsoleColor.Red; _count -= 1; Console.WriteLine($"递减后Counter: {_count}"); Console.ForegroundColor = ConsoleColor.White; } } } }
额外说明
- Task基于线程池实现,和Thread的核心区别在于线程复用,但lock的同步逻辑对两者都适用,本次问题的核心不在同步机制本身,而在任务等待
- 也可以使用
await Task.WhenAll(tasks)实现异步等待,但需要将Main方法修改为async Task Main()的形式
内容的提问来源于stack exchange,提问作者Alireza Molaei
相关产品推荐
相关产品推荐

