Parallel.ForEach含重试逻辑时无法显示全部数组值的原因排查
问题排查:Parallel.ForEach循环中文本框无法显示全部值
你遇到的核心问题是多线程竞态条件导致的字符串修改异常,以下是具体分析和解决方法:
问题原因
- 线程安全问题:
DisplayText是普通字符串类型,Parallel.ForEach会启动多个线程池线程同时执行Write方法。当多个线程执行DisplayText = DisplayText + "," + text时,字符串的拼接操作不是原子性的——线程会先读取当前DisplayText的值,拼接新内容,再赋值回去。如果多个线程同时读取到同一个旧值,后续的赋值操作就会覆盖彼此的结果,最终导致部分值丢失,显示内容随机变化。 - 无效的重试逻辑:你的
Write方法里的重试循环没有实际意义,只是等待两次1秒后才执行赋值,既没有实现“重试”的目的,还徒增了线程等待时间,但这不是导致内容缺失的直接原因。
修复方案
方案1:使用锁保护共享资源
在修改DisplayText的地方加锁,确保同一时间只有一个线程能修改它:
private readonly object _lockObj = new object(); public string DisplayText = "Numbers ="; private void Write(string text) { int maxRetryCount = 3; int retryCount = 0; int retryInterval = 1000; while (retryCount < maxRetryCount) { if(retryCount == maxRetryCount-1) { lock(_lockObj) { DisplayText = DisplayText + "," + text; } break; } Thread.Sleep(retryInterval); retryCount++; } }
方案2:使用线程安全的StringBuilder(配合锁)
字符串是不可变类型,频繁拼接效率低,改用StringBuilder并配合锁,既保证线程安全又提升性能:
private readonly object _lockObj = new object(); private StringBuilder _displayTextBuilder = new StringBuilder("Numbers ="); private void button1_Click(object sender, EventArgs e) { int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Start(numbers); textBox1.Text = _displayTextBuilder.ToString(); } private void Write(string text) { int maxRetryCount = 3; int retryCount = 0; int retryInterval = 1000; while (retryCount < maxRetryCount) { if(retryCount == maxRetryCount-1) { lock(_lockObj) { _displayTextBuilder.Append("," + text); } break; } Thread.Sleep(retryInterval); retryCount++; } }
额外说明
如果你的重试逻辑是为了模拟“失败重试”的场景,当前代码并没有实现真正的重试判断(比如没有判断操作是否失败),可以在循环里加入失败条件的检查,再决定是否重试。
内容的提问来源于stack exchange,提问作者charitht99 perera
相关产品推荐
相关产品推荐

