With parallel foreach
loops, developers can wrap the loop in a try
catch
statement. Care needs to be taken, however, because the Parallel.ForEach
will throw AggregatedException
, which has the exceptions it encounters over several threads rolled into one.
We will create a List<string>
object that contains a collection of machine IP addresses. The Parallel.ForEach
loop will check the IP addresses to see whether the machines on the other end of the given IP are alive. It does this by pinging the IP address. The method that performs the Parallel.ForEach
loop will also be given the minimum required alive machines as an integer value. If the minimum number of machines alive is not met, an exception is thrown.
Recipes
class, add a method called CheckClientMachinesOnline()
that takes as parameters a List<string>
collection of IP addresses and an integer that specifies the minimum number of machines required to be online. Add a second method called MachineReturnedPing()
that will receive an IP address to ping. For our purpose, we will just return false
to mimic a dead machine (the ping to the IP address timed out):public class Recipes { public void CheckClientMachinesOnline(List<string> ipAddresses, int minimumLive) { } private bool MachineReturnedPing(string ip) { return false; } }
CheckClientMachinesOnline()
method, add the Parallel.ForEach
loop and create the ParallelOptions
variable, which will specify the degree of parallelism. Wrap all this code inside a try
catch
statement and catch AggregateException
:try { int machineCount = ipAddresses.Count(); var options = new ParallelOptions(); options.MaxDegreeOfParallelism = machineCount; int deadMachines = 0; Parallel.ForEach(ipAddresses, options, ip => { }); } catch (AggregateException aex) { WriteLine("An AggregateException has occurred"); throw; }
Parallel.ForEach
loop, write the code to check whether the machine is online by calling the MachineReturnedPing()
method. In our example, this method will always return false
. You will notice that we are keeping track of the offline machine count via the Interlocked.Increment
method. This is just a way of incrementing a variable across the threads of the Parallel.ForEach
loop:if (MachineReturnedPing(ip)) { } else { if (machineCount - Interlocked.Increment(ref deadMachines) < minimumLive) { WriteLine($"Machines to check = {machineCount}"); WriteLine($"Dead machines = {deadMachines}"); WriteLine($"Minimum machines required = {minimumLive}"); WriteLine($"Live Machines = {machineCount - deadMachines}"); throw new Exception($"Minimum machines requirement of {minimumLive} not met"); } }
Recipes
class will look like this:public class Recipes { public void CheckClientMachinesOnline(List<string> ipAddresses, int minimumLive) { try { int machineCount = ipAddresses.Count(); var options = new ParallelOptions(); options.MaxDegreeOfParallelism = machineCount; int deadMachines = 0; Parallel.ForEach(ipAddresses, options, ip => { if (MachineReturnedPing(ip)) { } else { if (machineCount - Interlocked.Increment(ref deadMachines) < minimumLive) { WriteLine($"Machines to check = {machineCount}"); WriteLine($"Dead machines = {deadMachines}"); WriteLine($"Minimum machines required = {minimumLive}"); WriteLine($"Live Machines = {machineCount - deadMachines}"); throw new Exception($"Minimum machines requirement of {minimumLive} not met"); } } }); } catch (AggregateException aex) { WriteLine("An AggregateException has occurred"); throw; } } private bool MachineReturnedPing(string ip) { return false; } }
List<string>
object to store a collection of dummy IP addresses. Instantiate your Recipes
class and call the CheckClientMachinesOnline()
method, passing the collection of IP addresses and a minimum number of machines required to be online to it:List<string> ipList = new List<string>(); for (int i = 0; i <= 10; i++) { ipList.Add($"10.0.0.{i.ToString()}"); } try { Chapter7.Recipes oRecipe = new Chapter7.Recipes(); oRecipe.CheckClientMachinesOnline(ipList, 2); } catch (Exception ex) { WriteLine(ex.InnerException.Message); } ReadLine();
From the console window output, you can see that the minimum number of machines required to be online was not achieved. The application then threw an exception and caught it from the Parallel.ForEach
loop. Being able to handle exceptions in parallel loops such as this one is essential to maintain the stability of your application by being able to handle exceptions as they occur.
We encourage you to play around a little with the Parallel.ForEach
loop and drill into some of the inner methods of the AggregareException
class to really understand it better.
18.220.124.177