Parallel.ForEach IndexOutOfRangeException

时间:2015-03-05 13:15:48

标签: c# winforms

我尝试使用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();

这是我在de console中看到的:

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

3 个答案:

答案 0 :(得分:3)

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

问问自己

时会发生什么
dictLogs.Add(ID, new List<string>());

在同一时间被调用。

您与

存在同样的问题
Logs[logname]++;

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

您的ID已存在异常我认为是因为这个

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

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

另外

evlog.Source = logname;

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

foreach (EventLogEntry message in evlog.Entries)

说实话,我会说在炸毁宇宙之前取出并行循环。

答案 1 :(得分:1)

我希望这个集合不是线程安全的,是什么让你觉得它是什么?

处理邮件时,您的操作很可能会以某种意外的方式更改集合。

当1个线程完成工作时,你想通过编写复杂的多线程代码来实现什么目标?

答案 2 :(得分:1)

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