A race condition in C# occurs when two or more threads access shared data simultaneously, and the outcome of the program depends on the unpredictable timing of these threads. This can lead to inconsistent or incorrect results, making race conditions a critical problem in multi-threaded applications.
In this article, we will learn everything in practice and will try not just to understand but also to resolve the race condition and critical section problems in .NET.
How Race Conditions Occur?
Race conditions typically occur when the following conditions are met.
- Shared Resource: Two or more threads are trying to read, write, or modify the same shared resource (e.g., a variable, object, or file).
- Concurrent Execution: The threads execute concurrently without proper synchronization mechanisms to control their access to the shared resource.
Race conditions occur when multiple threads concurrently access and modify shared data, leading to unpredictable results.
They arise due to the lack of synchronization, where threads interleave in a way that causes operations to be performed out of the expected order.
A critical section in C# refers to a block of code that must be executed by only one thread at a time to prevent data corruption or inconsistent results due to concurrent access. When multiple threads access shared resources, such as variables or objects, and at least one thread modifies those resources, a critical section ensures that only one thread can execute the code block that accesses the shared resource at a time. This is crucial for maintaining the integrity of the shared data.
Let's directly switch to our example below and explore both worlds.
public class Transaction
{
public bool IsDone { get; set; }
public void Transfer(decimal amount)
{
if (!IsDone)//critical section
{
Console.WriteLine($"Transaction operation started in thread number = {Environment.CurrentManagedThreadId}");
TransferInternally(amount);
Console.WriteLine($"Transaction operation ended in thread number = {Environment.CurrentManagedThreadId}");
IsDone = true;
}
}
private void TransferInternally(decimal amount)
{
Console.WriteLine($"TransferInternally in thread...{Environment.CurrentManagedThreadId}, the amount = {amount}");
Console.WriteLine($"TransferInternally is done in thread...{Environment.CurrentManagedThreadId}, the amount = {amount}");
}
}
In the provided code, the critical section and the race condition problem relate to how multiple threads might interact with the Transaction class, particularly with the IsDone property and the Transfer method.
Critical Section
A critical section is a part of the code that accesses shared resources (in this case, the IsDone property) and must not be executed by more than one thread at a time. The critical section in your code is.
This block of code is critical because it checks and updates the IsDone property. If multiple threads access this code simultaneously without proper synchronization, it could lead to inconsistent or incorrect behavior.
Race Condition Problem
A race condition occurs when the outcome of a program depends on the timing or sequence of threads executing. In this code, a race condition could happen if multiple threads call the Transfer method at the same time.
Scenario Leading to a Race Condition
- Thread 1 checks the IsDone property and finds it to be false.
- Thread 1 proceeds with the transaction, outputting the start message and entering the TransferInternally method.
- Thread 2 then checks the IsDone property before Thread 1 has finished and still finds it to be false.
- Thread 2 also proceeds with the transaction, despite Thread 1 already handling it.



Mariusz PostolPosted Aug 28, 2024, 7:07 PM
"A critical section in C# refers to a block of code that must be executed by only one thread..." - it is not true - you must consider time. In C# but in Java, Algol, and Fortran it doesn't apply.
Mariusz PostolPosted Aug 28, 2024, 7:03 PM
What is the difference between concurrent and sequential programming? The question refers to compile time, not run time.
Mariusz PostolPosted Aug 28, 2024, 7:00 PM
"Shared Resource: Two or more threads are trying to read...." - in the case of immutable data it is not true.
Mariusz PostolPosted Aug 28, 2024, 6:57 PM
"This can lead to inconsistent or incorrect results" - do you think that if the result is inconsistent it is correct? What is the difference between inconsistent and incorrect results?
Mariusz PostolPosted Aug 28, 2024, 6:55 PM
You said "A race condition in C# occurs when two or more threads access shared data" - what is the difference between the race condition and the critical section problem? The critical section problem in software engineering arises when multiple concurrent threads access shared resources. My concern is if it is directly coupled with the C# programming language.