我不确定问题究竟在哪里,我想通过搜索" Parallel.ForEach"抛出错误,在几个系统上程序运行正常,但在我的VPS上,应用程序每次都会崩溃几秒钟。
private void bgWorkerCheckURLs_DoWork(object sender, DoWorkEventArgs e)
{
try
{
string action = e.Argument.ToString();
if (action == "wraith_check_links")
{
int unidentified = 1;
int identified = 1;
Parallel.ForEach(dgView.Rows.Cast<DataGridViewRow>(), (DataGridViewRow dataGridViewRow, ParallelLoopState parallelLoopState) =>
{
var backgroundWorker = sender as BackgroundWorker;
if (backgroundWorker.CancellationPending)
{
e.Cancel = true;
parallelLoopState.Break();
toolStripStatusLabel.Text = "Cancelling...";
}
else
{
List<string> urls;
string url = dataGridViewRow.Cells["url"].Value.ToString();
UrlRow urlRow = CheckUrl(url);
string platform = urlRow.Platform;
Invoke((Action)(() =>
{
dataGridViewRow.Cells["platform"].Value = platform;
dataGridViewRow.DefaultCellStyle.BackColor = urlRow.BackColor;
dataGridViewRow.DefaultCellStyle.ForeColor = urlRow.ForeColor;
if (platform == "UNIDENTIFIED")
{
lblPlatformsUnIdentified.Text = unidentified.ToString();
Interlocked.Increment(ref unidentified);
}
else
{
lblPlatformsIdentified.Text = identified.ToString();
Interlocked.Increment(ref identified);
}
}));
if (platforms.ContainsKey(platform))
{
urls = platforms[platform];
}
else
{
urls = new List<string>();
}
urls.Add(url);
platforms[platform] = urls;
}
});
}
}
catch (Exception ex)
{
Helpers.returnMessage(ex.Message);
}
}
技术细节是:
问题签名:
问题事件名称:CLR20r3
问题签名01:wraithplatformidentifier.exe
问题签名02:1.0.0.1
问题签名03:563f8d36
问题签名04:系统
问题签名05:4.0.30319.17929
问题签名06:4ffa5c88
问题签名07:23f8
问题签名08:59
问题签名09:System.AggregateException
操作系统版本:6.1.7601.2.1.0.274.10
区域设置ID:1033
附加信息1:0a9e
其他资料2:0a9e372d3b4ad19135b953a78882e789
其他资料3:0a9e
其他资料4:0a9e372d3b4ad19135b953a78882e789
它只会在VPS上崩溃,但如果我遗漏了错误,它可能会出现在更多系统上。
谁能看到我做错了什么?
谢谢你们
格雷厄姆
答案 0 :(得分:0)
我看到至少有3个潜在的线程不安全的地方。
lblPlatformsUnIdentified.Text = unidentified.ToString();
lblPlatformsIdentified.Text = identified.ToString();
这些控件可能会被不同的线程同时更改。
platforms[platform] = urls;
看起来平台是全球列表。多个线程可能正在尝试更新相同的索引。
要快速测试,请创建一个全局互斥:
System.Threading.Mutex mutex = new System.Threading.Mutex();
并将这些线放在这些可能的问题区域中:
mutex.WaitOne();
mutex.ReleaseMutex();
所以你的第一个标签更新将如下所示:
mutex.WaitOne();
lblPlatformsUnIdentified.Text = unidentified.ToString();
mutex.ReleaseMutex();