Skip to main content

Process and Thread Synchronization

Introduction​

When multiple threads or processes access shared resources, their access must be coordinated to avoid concurrency issues.

Concurrency Issues​

Race Condition​

When the result depends on the undetermined order of execution.

Thread 1                 Thread 2
-------- --------
Read counter (= 5)
Read counter (= 5)
Increment (= 6)
Increment (= 6)
Write (= 6)
Write (= 6)

Result: 6 instead of 7!

Critical Section​

Code area that accesses a shared resource and must be executed by only one thread at a time.

Deadlock​

Situation where two threads wait for each other indefinitely.

Thread 1: Holds A, waits for B
Thread 2: Holds B, waits for A
-> Permanent block!

Windows Synchronization Mechanisms​

Overview​

MechanismScopeUsage
Critical SectionIntra-processFast access, same process
MutexInter-processMutual exclusion, named
SemaphoreInter-processMultiple access control
EventInter-processSignaling
InterlockedIntra-processSimple atomic operations

Critical Section​

Concept​

Lightweight mechanism to synchronize threads within the same process.

Characteristics​

  • Faster than Mutex
  • Limited to a single process
  • Unnamed

Usage (C/C++)​

CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);

EnterCriticalSection(&cs);
// Critical section - one thread at a time
counter++;
LeaveCriticalSection(&cs);

DeleteCriticalSection(&cs);

In PowerShell (simulation)​

# Using [System.Threading.Monitor]
$lockObj = New-Object Object
$counter = 0

[System.Threading.Monitor]::Enter($lockObj)
try {
# Critical section
$counter++
}
finally {
[System.Threading.Monitor]::Exit($lockObj)
}

Mutex (Mutual Exclusion)​

Concept​

Synchronization object allowing mutual exclusion between processes.

Characteristics​

  • Can be named (accessible between processes)
  • Slower than Critical Section
  • Deadlock detection possible

Usage in PowerShell​

# Create or open a named mutex
$mutexName = "Global\MyMutex"
$mutex = New-Object System.Threading.Mutex($false, $mutexName)

try {
# Wait for the mutex (timeout 5 seconds)
if ($mutex.WaitOne(5000)) {
try {
Write-Host "Mutex acquired - critical section"
# Exclusive work here
Start-Sleep -Seconds 2
}
finally {
$mutex.ReleaseMutex()
Write-Host "Mutex released"
}
}
else {
Write-Host "Timeout - mutex not acquired"
}
}
finally {
$mutex.Close()
}

Named vs Anonymous Mutex​

TypeNameScope
AnonymousNoneThreads of the same process
Local"Local\Name"User session
Global"Global\Name"All system processes

Semaphore​

Concept​

Allows limiting the number of simultaneous accesses to a resource.

Difference with Mutex​

MutexSemaphore
1 access onlyN simultaneous accesses
Single ownerNo owner

Usage in PowerShell​

# Semaphore with 3 slots
$semName = "Global\MySemaphore"
$semaphore = New-Object System.Threading.Semaphore(3, 3, $semName)

try {
if ($semaphore.WaitOne(5000)) {
try {
Write-Host "Slot acquired in semaphore"
# Work limited to 3 simultaneous threads
Start-Sleep -Seconds 2
}
finally {
$semaphore.Release()
Write-Host "Slot released"
}
}
}
finally {
$semaphore.Close()
}

Use Cases​

  • Database connection pool
  • Limiting simultaneous downloads
  • Control of limited resources

Event​

Concept​

Allows a thread to signal an event to other threads.

Event Types​

TypeBehavior
AutoResetReleases one thread then resets to non-signaled
ManualResetRemains signaled until explicit reset

Usage in PowerShell​

# ManualReset Event
$eventName = "Global\MyEvent"
$event = New-Object System.Threading.EventWaitHandle(
$false, # Initial state: non-signaled
[System.Threading.EventResetMode]::ManualReset,
$eventName
)

# In the producer thread
$event.Set() # Signal
$event.Reset() # Reset to non-signaled

# In the consumer thread
if ($event.WaitOne(5000)) {
Write-Host "Event received!"
}

$event.Close()

Interlocked Operations​

Concept​

Atomic operations on variables, without the need for explicit lock.

Available Operations​

OperationDescription
IncrementIncrements by 1
DecrementDecrements by 1
AddAdds a value
ExchangeExchanges values
CompareExchangeConditional exchange

Usage in PowerShell​

# Atomic increment
$counter = 0
[System.Threading.Interlocked]::Increment([ref]$counter)
Write-Host "Counter: $counter"

# Atomic add
[System.Threading.Interlocked]::Add([ref]$counter, 10)
Write-Host "Counter after add: $counter"

# Atomic exchange
$oldValue = [System.Threading.Interlocked]::Exchange([ref]$counter, 100)
Write-Host "Old value: $oldValue, New: $counter"

Best Practices​

Avoid Deadlocks​

  1. Consistent order: Always acquire locks in the same order
  2. Timeouts: Use timeouts to detect blocks
  3. Minimize: Keep critical sections short

Example of avoided deadlock​

# BAD - risk of deadlock
# Thread 1: Lock A then Lock B
# Thread 2: Lock B then Lock A

# GOOD - consistent order
# Thread 1: Lock A then Lock B
# Thread 2: Lock A then Lock B (same order!)

Performance​

MechanismPerformanceUse Case
InterlockedVery fastSimple operations
Critical SectionFastSame process
MutexMediumInter-process
SemaphoreMediumLimited multiple access

Problem Detection​

Process Explorer​

  • View > Show Lower Pane
  • Handle view: see synchronization handles

WinDbg​

!locks          # Display locks
!handle # Display handles
!analyze -hang # Analyze a hang/deadlock

Performance Monitor​

Useful counters:

  • Process > Handle Count
  • Thread > Context Switches/sec

Exercises​

  1. Create a script with two PowerShell jobs using a shared mutex
  2. Implement a thread-safe counter with Interlocked
  3. Create a semaphore that limits to 2 simultaneous executions

References​