Amicable
Amicable

Reputation: 3091

Parallel.Foreach loop never ends

My code executes as I would expect on smaller loops, but when I iterate through larger IP Ranges the process seems to stop short and never complete.

The program keeps running, and no exceptions are thrown.

public void Discover()
{
    Int32 MaxThreadCount     = 20, 
        DevicesProcessed     = 0;
    List<String> IPAddresses = GetIPAddresses(IPRangesToCheck).ToList();

    using (cts = new CancellationTokenSource())
    {

        ParallelOptions po = new ParallelOptions();
        po.MaxDegreeOfParallelism = MaxThreadCount;
        po.CancellationToken = cts.Token;

        try
        {
            var deviceInfo = new DeviceInfo();

            Parallel.ForEach(IPAddresses, po, (item, loopState) =>
            {
                try
                {
                    Console.WriteLine("DevicesProcessed: {0}, IPAddresses.Count: {1}", DevicesProcessed, IPAddresses.Count.ToString());
                    if (DevicesProcessed >= IPAddresses.Count)
                    {
                        Console.WriteLine("!!!THRESHOLD REACHED!!!");
                        cts.Cancel();
                    }

                    if (loopState.ShouldExitCurrentIteration || loopState.IsExceptional)
                    {
                        loopState.Stop();
                        DiscoverStatus = Devices.DiscoverState.Stopped;
                    }

                    var response = CheckIPAndReturnInfo(item);

                    if (loopState.ShouldExitCurrentIteration || loopState.IsExceptional)
                    {
                        loopState.Stop();
                        DiscoverStatus = Devices.DiscoverState.Stopped;
                    }

                    if (response != null)
                    {
                        FoundDevices.Add(response);
                        Console.WriteLine(
                            "Device Count {0}, IP Address {1}",
                            DevicesProcessed,
                            item);
                    }

                    Interlocked.Increment(ref DevicesProcessed);
                }
                catch (Exception ex)
                {
                    Console.Write("Error! = " + ex.Message);

                    if (deviceInfo.State == CommunicationState.Faulted)
                    {
                        loopState.Stop();
                    }
                }
            });

            RaiseAllItemsCompleteEvent();

        }
        catch (AggregateException aggEx)
        {
            Console.WriteLine("Parrallel Exception!: " + aggEx);
        }
    }
}

When I use the range 172.16.0.0 to 172.16.255.255 there are 65536 IP Addresses to check. The program gets to 65519 before ceasing to process any more addresses and not progressing further in the code. At this point no breakpoints are hit anywhere in the code.

The if (DevicesProcessed >= IPAddresses.Count) section was an attempt to manually cancel the loop once it was finished, but unfortunately it doesn't get that far. Canceling, before this point does work correctly.

I have been unable to find anyone else experiencing this sort of issue with Parallel tasks and I am quite stumped. Any advice on ways to further debug the issue would be appreciated.

I have added a stopwatch to my CheckIPAndReturnInfo class, to see how long it takes to elapse. This is where the Start: and End: output text is generated. Here is a sample of the output, where the program falls over:

DevicesProcessed: 65515, IPAddresses.Count: 65536
Start : 172.16.114.94
End : 172.16.114.94 Elaspsed: 00:00:01.4247110
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
End : 172.16.114.60 Elaspsed: 00:00:07.0803977
DevicesProcessed: 65517, IPAddresses.Count: 65536
Start : 172.16.114.61
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
End : 172.16.114.76 Elaspsed: 00:00:07.0807436
DevicesProcessed: 65518, IPAddresses.Count: 65536
Start : 172.16.114.77
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
The thread '<No Name>' (0x1664) has exited with code 0 (0x0).
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
End : 172.16.114.61 Elaspsed: 00:00:07.0806001
DevicesProcessed: 65519, IPAddresses.Count: 65536
Start : 172.16.114.62
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
End : 172.16.114.77 Elaspsed: 00:00:07.0807928
DevicesProcessed: 65520, IPAddresses.Count: 65536
Start : 172.16.114.78
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
The thread '<No Name>' (0xf90) has exited with code 0 (0x0).
The thread '<No Name>' (0x1b24) has exited with code 0 (0x0).
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
End : 172.16.114.62 Elaspsed: 00:00:07.0806679
A first chance exception of type 'Lextm.SharpSnmpLib.Messaging.TimeoutException' occurred in SharpSnmpLib.dll
End : 172.16.114.78 Elaspsed: 00:00:07.0804395
The thread '<No Name>' (0x1518) has exited with code 0 (0x0).
The thread '<No Name>' (0x1e1c) has exited with code 0 (0x0).
The thread '<No Name>' (0x1190) has exited with code 0 (0x0).
The thread '<No Name>' (0x1218) has exited with code 0 (0x0).
The thread '<No Name>' (0x1c68) has exited with code 0 (0x0).
The thread '<No Name>' (0x1b20) has exited with code 0 (0x0).
The thread '<No Name>' (0xa14) has exited with code 0 (0x0).
The thread '<No Name>' (0x185c) has exited with code 0 (0x0).
The thread '<No Name>' (0x430) has exited with code 0 (0x0).

Upvotes: 1

Views: 2527

Answers (2)

Darek
Darek

Reputation: 4797

  1. Do not use IsCompleted in your if statement. Just put RaiseAllItemsCompleteEvent after Parallel.ForEach.

  2. In your exception handler, don't re-throw the exception, as it will cause Parallel to error out. Just use loopState.Stop.

Silly example:

Parallel.ForEach(Enumerable.Range(0, 100),
    (i, state) =>
    {
        Console.WriteLine(i);
        if(i==11) state.Stop();
    });
RaiseAllItemsCompleteEvent();

And in your conditional checks, just use if(loopState.IsStopped). Given your try/catch block, it would be difficult to hit IsExceptional.

Finally, because you are running in Parallel, you must use Interlocked.Increment(ref DevicesProcessed). Otherwise, the count will not be accurate.

Upvotes: 2

Ajay Kelkar
Ajay Kelkar

Reputation: 4621

cts.Cancel() can throw AggregateException

Catch it inner try as well and see if its hits there, if that is happening in your current code absence of inner `AggregateException' it will go infinite loop.

Upvotes: 0

Related Questions