Parallelism Safely: Utilize ConcurrentBag<T> or lock to Thread-Safe Data Accumulation
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
var inputList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var resultList = new List<double>();
Parallel.ForEach(inputList, number =>
{
// Perform computationally intensive operation
double result = Math.Pow(number, 2);
// Add the result to the shared List<double>
resultList.Add(result);
});
// Process or analyze the resultList
Console.WriteLine($"Processed results count: {resultList.Count}");
}
}
What did you think? Any error in the above code? Maybe not, but there is a issue here.
Due to concurrent access, the code may encounter issues such as index out-of-range exceptions, incorrect results, or race conditions. This approach is not suitable for concurrent access scenarios.
How you can resolve this?
Solution 1: By using the lock keyword and specifying the lockObject, we ensure that only one thread can access the critical section at a time, preventing concurrent modifications.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
private static object lockObject = new object();
public static void Main()
{
var inputList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var resultList = new List<double>();
Parallel.ForEach(inputList, number =>
{
// Perform computationally intensive operation
double result = Math.Pow(number, 2);
// Update the result List<double> with lock
lock (lockObject)
{
resultList.Add(result);
}
});
// Process or analyze the resultList
Console.WriteLine($"Processed results count: {resultList.Count}");
}
}
Solution 2: To overcome the challenges of concurrent access, we can utilize the ConcurrentBag<T> collection instead of List<T>. ConcurrentBag<T> provides thread-safe adding of elements and eliminates the need for manual synchronization.
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
var inputList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var resultList = new ConcurrentBag<double>();
Parallel.ForEach(inputList, number =>
{
// Perform computationally intensive operation
double result = Math.Pow(number, 2);
// Add the result to the ConcurrentBag<double>
resultList.Add(result);
});
// Process or analyze the resultList
Console.WriteLine($"Processed results count: {resultList.Count}");
}
}
Is’t it interesting?