C#多线程中count变量非100倍数?加锁后仍异常求解
多线程场景下count值不符合预期的问题分析与解决
问题重现
以下是出现问题的C#代码:
private static readonly object ThreadKey = new object(); private void PlayVideo() { int count = 0; for (int y = 1; y < 1000; y++) { lock(ThreadKey) { count++; if ((count % 100) == 0) { Task.Run(() => TestTh(count)); } } } } private void TestTh(int count) { // 发现count并非100的倍数 System.IO.File.WriteAllText(@"D:\USER\Desktop\Myfolder\" + count.ToString()+".txt", count.ToString()); }
问题原因
这不是锁的问题,核心原因是闭包捕获的是变量的引用而非当前值:
- 当
Task.Run(() => TestTh(count))被调用时,lambda表达式捕获的是count变量的引用,而非此时count的具体数值。 - 锁块仅保证
count++和条件判断是原子操作,但Task的执行是异步的,会在后续某个时间点运行。在Task执行前,for循环会继续执行,count会被多次自增,导致Task最终读取的count值已经不是触发条件时的100倍数。
解决方案
在锁块内创建临时变量存储当前的count值,让lambda捕获这个临时变量(临时变量的值在当前锁块内是固定的,不会被后续循环修改):
修改后的代码:
private static readonly object ThreadKey = new object(); private void PlayVideo() { int count = 0; for (int y = 1; y < 1000; y++) { lock(ThreadKey) { count++; if ((count % 100) == 0) { // 创建临时变量存储当前count值 int currentCount = count; Task.Run(() => TestTh(currentCount)); } } } } private void TestTh(int count) { System.IO.File.WriteAllText(@"D:\USER\Desktop\Myfolder\" + count.ToString()+".txt", count.ToString()); }
这样每个Task都会拿到触发条件时的准确count值,保证写入文件的数值都是100的倍数。
内容的提问来源于stack exchange,提问作者WorkHardMan
相关产品推荐
相关产品推荐

