Parallel.ForEach IndexOutOfRangeException

本文关键字:IndexOutOfRangeException ForEach Parallel | 更新日期: 2024-10-21 08:50:13

我正试图用Parallel.ForEach遍历我的事件日志。但它随机停止,ForEach上出现错误IndexOutOfRangeException。

这个:

foreach (EventLogEntry message in evlog.Entries)

有时它在第一次通过环路时停止,有时在已经通过环路44次之后停止。

此外,我有时会得到一个错误,即给定的ID已经存在。

这是我的完整代码:

string ID = null;
Logs.Add("System", 0);
Logs.Add("Application", 1000);
Logs.Add("Setup", 2000);
Logs.Add("Forwarded Events", 3000);  
EventLog evlog = new EventLog();
evlog.MachineName = ".";  
Parallel.ForEach(Logs.Keys, logname =>
{
    System.Threading.Thread.Sleep(1000);
    evlog.Source = logname;
    string lognameWithoutSpaces = logname.Replace(" ", "");
    foreach (EventLogEntry message in evlog.Entries)
    {
        string type = message.EntryType.ToString();
        if (type == "0" | type == "Warning")
        {
            ID = lognameWithoutSpaces + "_" + Logs[logname].ToString();
            Console.WriteLine("ID: " + ID);
            dictLogs.Add(ID, new List<string>());
            dictLogs[ID].Add(evlog.Log);
            dictLogs[ID].Add(message.Source);
            dictLogs[ID].Add(message.InstanceId.ToString());
            dictLogs[ID].Add(type);
            dictLogs[ID].Add(message.UserName);
            dictLogs[ID].Add(message.TimeGenerated.ToString());
            dictLogs[ID].Add(message.Category);
            dictLogs[ID].Add(message.MachineName);
            dictLogs[ID].Add(message.Message);
            Logs[logname]++;
        }
    }
});
dictLogs.Clear();

这就是我在控制台上看到的:

ID: ForwardedEvents_3000
ID: System_0
ID: Setup_2000
ID: Application_1000
'DashboardBackEnd.vshost.exe' (CLR v4.0.30319: DashboardBackEnd.vshost.exe):    Loaded 'C:'Windows'Microsoft.Net'assembly'GAC_MSIL'System.resources'v4.0_4.0.0.0_nl_b77a5c561934e089'System.resources.dll'. Module was built without symbols.
A first chance exception of type 'System.Collections.Generic.KeyNotFoundException' occurred in mscorlib.dll
A first chance exception of type 'System.IndexOutOfRangeException' occurred in System.dll

Parallel.ForEach IndexOutOfRangeException

dictLogs由多个线程同时添加到。如果这是一本普通的字典,这会给你带来问题。

问问自己会发生什么

dictLogs.Add(ID, new List<string>());

在完全相同的时间调用。

也有同样的问题

Logs[logname]++;

其中相同的条目将由多个线程更新。但是,这不应导致IndexOutOfRangeException,而是会导致不正确的计数。

你的身份证已经存在,我想是因为这个

ID = lognameWithoutSpaces + "_" + Logs[logname].ToString();

日志[logname]可能同时具有相同的计数。因此,这将导致输入重复的密钥

还有

evlog.Source = logname;

可能不会引起任何异常,但它会给你不正确的结果,因为它可能在到达循环之前被另一个线程更改:

foreach (EventLogEntry message in evlog.Entries)

老实说,在你炸毁宇宙之前,我会说去掉平行循环

我认为这个集合不是线程安全的,你凭什么认为它是线程安全的?

此外,您在处理消息时的操作很可能会以某种意想不到的方式更改集合。

当一个线程可以完成这项工作时,您试图通过编写复杂的多线程代码来实现什么?

并行循环的每个实例都在写入同一个evlog。因此,一个循环正在设置Source,而另一个循环已经在运行。