Protect a shared counter while two threads increment it.

lock A `lock` block lets only one thread update the guarded state at a time.

Lock Counter

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

class Program
{
    static readonly object Gate = new object();
    static int counter;
    static int rounds;

    static void Increment()
    {
        for (int step = 0; step < rounds; step++)
        {
            lock (Gate)
            {
                int next = counter + 1;
                counter = next;
            }
        }
    }

    static void Main()
    {
        int increments = 2;
        rounds = increments;
        counter = 0;

        Thread first = new Thread(Increment);
        Thread second = new Thread(Increment);

        first.Start();
        second.Start();

        first.Join();
        second.Join();

        Console.WriteLine($"increments={increments}");
        Console.WriteLine($"counter={counter}");
    }
}
using System;
using System.Threading;

class Program
{
    static readonly object Gate = new object();
    static int counter;
    static int rounds;

    static void Increment()
    {
        for (int step = 0; step < rounds; step++)
        {
            lock (Gate)
            {
                int next = counter + 1;
                counter = next;
            }
        }
    }

    static void Main()
    {
        int increments = 1;
        rounds = increments;
        counter = 0;

        Thread first = new Thread(Increment);
        Thread second = new Thread(Increment);

        first.Start();
        second.Start();

        first.Join();
        second.Join();

        Console.WriteLine($"increments={increments}");
        Console.WriteLine($"counter={counter}");
    }
}
using System;
using System.Threading;

class Program
{
    static readonly object Gate = new object();
    static int counter;
    static int rounds;

    static void Increment()
    {
        for (int step = 0; step < rounds; step++)
        {
            lock (Gate)
            {
                int next = counter + 1;
                counter = next;
            }
        }
    }

    static void Main()
    {
        int increments = 3;
        rounds = increments;
        counter = 0;

        Thread first = new Thread(Increment);
        Thread second = new Thread(Increment);

        first.Start();
        second.Start();

        first.Join();
        second.Join();

        Console.WriteLine($"increments={increments}");
        Console.WriteLine($"counter={counter}");
    }
}
  1. increments ← 2, rounds ← 2, counter ← 0, first ← System.Threading.Thread

    22static void Main()23{24    int increments→ 2 = 2; //@increments=1, 325    rounds→ 2 = increments2;26    counter→ 0 = 0;2728    Thread first→ System.Threading.Thread = new Thread(Increment);29    Thread second→ System.Threading.Thread = new Thread(Increment);3031    firstSystem.Threading.Thread.Start();32    secondSystem.Threading.Thread.Start();3334    firstSystem.Threading.Thread.Join();35    second.Join();
  2. next ← 1, counter ← 1

    pass 1 of 4
    11{12    for (int step0 = 0; step < rounds2; step++)13    {14        lock (Gate)15        {16            int next→ 1 = counter0 + 1;17            counter→ 1 = next1;18        }
    All 4 passes — pass 1 is the card above
    passstepnextcounter
    1010 1
    2121 2
    3032 3
    4143 4
  3. first.Join();

    34    firstSystem.Threading.Thread.Join();35    secondSystem.Threading.Thread.Join();3637    Console.WriteLine($"increments={increments2}");38    Console.WriteLine($"counter={counter4}");39}
    outputincrements=2
    counter=4
  1. increments ← 1, rounds ← 1, counter ← 0, first ← System.Threading.Thread

    22static void Main()23{24    int increments→ 1 = 1;25    rounds→ 1 = increments1;26    counter→ 0 = 0;2728    Thread first→ System.Threading.Thread = new Thread(Increment);29    Thread second→ System.Threading.Thread = new Thread(Increment);3031    firstSystem.Threading.Thread.Start();32    secondSystem.Threading.Thread.Start();
  2. next ← 1, counter ← 1

    pass 1 of 2
    11{12    for (int step0 = 0; step < rounds1; step++)13    {14        lock (Gate)15        {16            int next→ 1 = counter0 + 1;17            counter→ 1 = next1;18        }
  3. second.Start();

    31first.Start();32secondSystem.Threading.Thread.Start();
  4. first.Join();

    34firstSystem.Threading.Thread.Join();35second.Join();
  5. next ← 2, counter ← 2

    pass 2 of 2
    11{12    for (int step0 = 0; step < rounds1; step++)13    {14        lock (Gate)15        {16            int next→ 2 = counter1 + 1;17            counter→ 2 = next2;18        }
  6. first.Join();

    34    firstSystem.Threading.Thread.Join();35    secondSystem.Threading.Thread.Join();3637    Console.WriteLine($"increments={increments1}");38    Console.WriteLine($"counter={counter2}");39}
    outputincrements=1
    counter=2
  1. increments ← 3, rounds ← 3, counter ← 0, first ← System.Threading.Thread

    22static void Main()23{24    int increments→ 3 = 3;25    rounds→ 3 = increments3;26    counter→ 0 = 0;2728    Thread first→ System.Threading.Thread = new Thread(Increment);29    Thread second→ System.Threading.Thread = new Thread(Increment);3031    firstSystem.Threading.Thread.Start();32    secondSystem.Threading.Thread.Start();
  2. next ← 1, counter ← 1

    pass 1 of 6
    11{12    for (int step0 = 0; step < rounds3; step++)13    {14        lock (Gate)15        {16            int next→ 1 = counter0 + 1;17            counter→ 1 = next1;18        }
    All 6 passes — pass 1 is the card above
    passstepnextcounter
    1010 1
    2121 2
    3232 3
    4043 4
    5154 5
    6265 6
  3. second.Start();

    31first.Start();32secondSystem.Threading.Thread.Start();
  4. first.Join();

    34firstSystem.Threading.Thread.Join();35second.Join();
  5. first.Join();

    34    firstSystem.Threading.Thread.Join();35    secondSystem.Threading.Thread.Join();3637    Console.WriteLine($"increments={increments3}");38    Console.WriteLine($"counter={counter6}");39}
    outputincrements=3
    counter=6