Concurrency and Source Panels
Lock Counter
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
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}");
}
}
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();next ← 1, counter ← 1
pass 1 of 411{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 pass stepnextcounter1 0 1 0 → 1 2 1 2 1 → 2 3 0 3 2 → 3 4 1 4 3 → 4 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
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();next ← 1, counter ← 1
pass 1 of 211{12 for (int step0 = 0; step < rounds1; step++)13 {14 lock (Gate)15 {16 int next→ 1 = counter0 + 1;17 counter→ 1 = next1;18 }second.Start();
31first.Start();32secondSystem.Threading.Thread.Start();first.Join();
34firstSystem.Threading.Thread.Join();35second.Join();next ← 2, counter ← 2
pass 2 of 211{12 for (int step0 = 0; step < rounds1; step++)13 {14 lock (Gate)15 {16 int next→ 2 = counter1 + 1;17 counter→ 2 = next2;18 }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
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();next ← 1, counter ← 1
pass 1 of 611{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 pass stepnextcounter1 0 1 0 → 1 2 1 2 1 → 2 3 2 3 2 → 3 4 0 4 3 → 4 5 1 5 4 → 5 6 2 6 5 → 6 second.Start();
31first.Start();32secondSystem.Threading.Thread.Start();first.Join();
34firstSystem.Threading.Thread.Join();35second.Join();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