Parallelism Safely: Utilize ConcurrentBag<T> or lock to Thread-Safe Data Accumulation

Sajidur Rahman
2 min readJun 7, 2023

--

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?

--

--

No responses yet