Give each thread its own context value before storing a shared summary.

thread local `ThreadLocal<T>` stores a separate value for each thread while the main thread reads ordinary shared results after `Join`.

Thread Local Context

extra
ThreadLocalContext.cs
Replay: real traced execution (multi-file project)
using System;
using System.Threading;

class Program
{
    static readonly ThreadLocal<int> WorkerScore = new ThreadLocal<int>(() => 0);
    static int boost;
    static int alphaResult;
    static int betaResult;

    static void AlphaWorker()
    {
        WorkerScore.Value = boost + 10;
        alphaResult = WorkerScore.Value;
    }

    static void BetaWorker()
    {
        WorkerScore.Value = boost + 20;
        betaResult = WorkerScore.Value;
    }

    static void Main()
    {
        int extra = 3;
        boost = extra;

        Thread alpha = new Thread(AlphaWorker);
        Thread beta = new Thread(BetaWorker);

        alpha.Start();
        beta.Start();

        alpha.Join();
        beta.Join();

        int total = alphaResult + betaResult;
        Console.WriteLine($"extra={extra}");
        Console.WriteLine($"total={total}");
    }
}
using System;
using System.Threading;

class Program
{
    static readonly ThreadLocal<int> WorkerScore = new ThreadLocal<int>(() => 0);
    static int boost;
    static int alphaResult;
    static int betaResult;

    static void AlphaWorker()
    {
        WorkerScore.Value = boost + 10;
        alphaResult = WorkerScore.Value;
    }

    static void BetaWorker()
    {
        WorkerScore.Value = boost + 20;
        betaResult = WorkerScore.Value;
    }

    static void Main()
    {
        int extra = 1;
        boost = extra;

        Thread alpha = new Thread(AlphaWorker);
        Thread beta = new Thread(BetaWorker);

        alpha.Start();
        beta.Start();

        alpha.Join();
        beta.Join();

        int total = alphaResult + betaResult;
        Console.WriteLine($"extra={extra}");
        Console.WriteLine($"total={total}");
    }
}
using System;
using System.Threading;

class Program
{
    static readonly ThreadLocal<int> WorkerScore = new ThreadLocal<int>(() => 0);
    static int boost;
    static int alphaResult;
    static int betaResult;

    static void AlphaWorker()
    {
        WorkerScore.Value = boost + 10;
        alphaResult = WorkerScore.Value;
    }

    static void BetaWorker()
    {
        WorkerScore.Value = boost + 20;
        betaResult = WorkerScore.Value;
    }

    static void Main()
    {
        int extra = 7;
        boost = extra;

        Thread alpha = new Thread(AlphaWorker);
        Thread beta = new Thread(BetaWorker);

        alpha.Start();
        beta.Start();

        alpha.Join();
        beta.Join();

        int total = alphaResult + betaResult;
        Console.WriteLine($"extra={extra}");
        Console.WriteLine($"total={total}");
    }
}
  1. extra ← 3, boost ← 3, alpha ← System.Threading.Thread, beta ← System.Threading.Thread

    23static void Main()24{25    int extra→ 3 = 3; //@extra=1, 726    boost→ 3 = extra3;2728    Thread alpha→ System.Threading.Thread = new Thread(AlphaWorker);29    Thread beta→ System.Threading.Thread = new Thread(BetaWorker);3031    alphaSystem.Threading.Thread.Start();32    beta.Start();
  2. alphaResult ← 13

    11static void AlphaWorker()12{13    WorkerScore.Value = boost3 + 10;14    alphaResult→ 13 = WorkerScore.Value;15}
  3. alpha.Start();

    31alphaSystem.Threading.Thread.Start();32betaSystem.Threading.Thread.Start();3334alphaSystem.Threading.Thread.Join();35betaSystem.Threading.Thread.Join();
  4. betaResult ← 23

    17static void BetaWorker()18{19    WorkerScore.Value = boost3 + 20;20    betaResult→ 23 = WorkerScore.Value;21}
  5. total ← 36

    34    alpha.Join();35    betaSystem.Threading.Thread.Join();3637    int total→ 36 = alphaResult13 + betaResult23;38    Console.WriteLine($"extra={extra3}");39    Console.WriteLine($"total={total36}");40}
    outputextra=3
    total=36
  1. extra ← 1, boost ← 1, alpha ← System.Threading.Thread, beta ← System.Threading.Thread

    23static void Main()24{25    int extra→ 1 = 1;26    boost→ 1 = extra1;2728    Thread alpha→ System.Threading.Thread = new Thread(AlphaWorker);29    Thread beta→ System.Threading.Thread = new Thread(BetaWorker);3031    alphaSystem.Threading.Thread.Start();32    betaSystem.Threading.Thread.Start();3334    alphaSystem.Threading.Thread.Join();35    beta.Join();
  2. static void AlphaWorker()

    11static void AlphaWorker()12{13    WorkerScore.Value = boost1 + 10;14    alphaResult = WorkerScore.Value;
  3. alphaResult ← 11, betaResult ← 21

    12{13    WorkerScore.Value = boost1 + 10;14    alphaResult→ 11 = WorkerScore.Value;15}1617static void BetaWorker()18{19    WorkerScore.Value = boost1 + 20;20    betaResult→ 21 = WorkerScore.Value;21}
  4. total ← 32

    34    alphaSystem.Threading.Thread.Join();35    betaSystem.Threading.Thread.Join();3637    int total→ 32 = alphaResult11 + betaResult21;38    Console.WriteLine($"extra={extra1}");39    Console.WriteLine($"total={total32}");40}
    outputextra=1
    total=32
  1. extra ← 7, boost ← 7, alpha ← System.Threading.Thread, beta ← System.Threading.Thread

    23static void Main()24{25    int extra→ 7 = 7;26    boost→ 7 = extra7;2728    Thread alpha→ System.Threading.Thread = new Thread(AlphaWorker);29    Thread beta→ System.Threading.Thread = new Thread(BetaWorker);3031    alphaSystem.Threading.Thread.Start();32    betaSystem.Threading.Thread.Start();3334    alphaSystem.Threading.Thread.Join();35    beta.Join();
  2. static void AlphaWorker()

    11static void AlphaWorker()12{13    WorkerScore.Value = boost7 + 10;14    alphaResult = WorkerScore.Value;
  3. alphaResult ← 17, betaResult ← 27

    12{13    WorkerScore.Value = boost7 + 10;14    alphaResult→ 17 = WorkerScore.Value;15}1617static void BetaWorker()18{19    WorkerScore.Value = boost7 + 20;20    betaResult→ 27 = WorkerScore.Value;21}
  4. total ← 44

    34    alphaSystem.Threading.Thread.Join();35    betaSystem.Threading.Thread.Join();3637    int total→ 44 = alphaResult17 + betaResult27;38    Console.WriteLine($"extra={extra7}");39    Console.WriteLine($"total={total44}");40}
    outputextra=7
    total=44