In this lesson, you’ll learn how to maintain efficient, thread-safe local counters and buffers inside a parallel loop using thread-local initialization.
The Challenge of Shared State
When using Parallel.For or Parallel.ForEach, your code runs on multiple threads simultaneously. If you try to update a shared variable (like a counter) directly inside the loop, you encounter a "race condition." You could use the lock statement to make it thread-safe, but that forces your threads to wait in line, destroying the performance gains of parallelism.
The Solution: Thread-Local State
Instead of sharing one variable, you can give each thread its own "private" copy of a variable. The parallel loop initializes this state once for every thread involved, lets the thread work on its private copy without any locking, and finally merges the results at the end.
We achieve this using the localInit and localFinally parameters in Parallel.ForEach:
int[] numbers = Enumerable.Range(1, 1000).ToArray();
long totalSum = 0;
Parallel.ForEach(
numbers,
// 1. Initialize a local state (this runs once per thread)
() => 0,
// 2. Perform work using the local thread variable
(num, loopState, localSum) => localSum + num,
// 3. Merge the thread-local result back to the global sum
(localSum) => Interlocked.Add(ref totalSum, localSum)
);
How it Works
localInit: The delegate() => 0runs once for every thread. If 4 threads are processing your loop, 4 separatelocalSumvariables are created.- The Loop Body: The second delegate receives the
localSum. Because this is local to the thread, nolockis required; it is naturally thread-safe and incredibly fast. localFinally: Once a thread finishes its portion of the work, the last delegate executes. We useInterlocked.Addhere to safely combine the thread's final private sum into the maintotalSum. Because this only happens once per thread, the performance overhead is negligible compared to locking on every single iteration.
Key Takeaway: Use thread-local initialization to provide each parallel worker with its own private state, eliminating the need for slow, constant locking.