Reputation: 157
I am experimenting with the signaling constructs of .NET and tried to do a simple coordination between two threads, however something is wrong and the results are all over the place with the program sometimes locking up. I guess there is some sort of race condition going on, but would like for someone to explain what's happening.
private static readonly AutoResetEvent manual = new AutoResetEvent(false);
private static int num;
public static async Task Main()
{
await Task.WhenAll(Task.Run(Method1), Task.Run(Method2));
}
private static void Method1()
{
num = 100;
manual.Set();
manual.WaitOne();
num -= 1000;
manual.Set();
}
private static void Method2()
{
manual.WaitOne();
var into = num;
num += into / 2;
manual.Set();
manual.WaitOne();
Console.WriteLine($"final value of num {num}");
}
Upvotes: 0
Views: 61
Reputation: 1567
Yes, this is a race condition.
Method 1 Begins
Method 2 cant start before Method 1 because it calls WaitOne in the beginning and the AutoResetEvent is not in the signaled state
Method 1 assigns num = 100
Method 1 sets AutoResetEvent. This notifies a waiting thread that an event has occurred.
Rest of work will be divided into multiple Scenarios.
Scenario 1:
Method 1 calls WaitOne, consumes AutoResetEvent signaled state and goes to the next line, AutoResetEvent resets.
Method 1 decreases num by 1000 (num = -900 now)
Method 1 signals AutoResetEvent
Method 2 can start cause AutoResetEvent is signlaed. AutoResetEvent resets after Method 2 getting notified.
Method 2 assigns into = num (into = -900)
Method 2 increases num by (into / 2) which makes the final result of num = -1350 (num = -900 - 450)
Method 2 signals AutoResetEvent
Method 2 consumes AutoResetEvent signaled state
Method 2 prints final value
The result is -1350 and the program terminates because both tasks finished in this Scenario.
Scenario 2:
Instead of method 1, Method 2 calls WaitOne and continues. AutoResetEvent resets.
Method 1 cant go to the next line because it is blocked by WaitOne
Method 2 assigns num to into (into = 100 now)
Method 2 increases num by into/2 (num = 100 + 50 = 150)
Method 2 sets AutoResetEvent.
Here, Scenario 2 will be divided into multiple Scenarios. Scenarios2-1 and Scenarios2-2
Scenario 2-1:
Method 1 gets notified and decrease num by 1000 (num = 150 - 1000 = -850)
Method 1 sets AutoResetEvent.
Method 2 gets notified and prints the result.
The result is -850 and the program terminates, because both tasks finished in this Scenario.
Scenario 2-2:
Method 2 gets notified and prints the result.
Method 1 will be blocked until someone somewhere set the AutoResetEvent.
The result is 150 and the program does NOT terminate, because the first task is not finished yet.
Upvotes: 2