SET
SET

Reputation: 157

Need help understanding AutoResetEvent behaviour

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

Answers (1)

Avestura
Avestura

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

Related Questions