Boolean flags are the obsolete way to synchronize two threads. It causes race conditions when one thread can read a value of false while other thread is updating the value to true;
Since your case it not straightforward (B shouldn't way for B to end, while A should wait), then I would change the class use a Semaphore like this:
public class MyClass { private SemaphoreSlim semaphore = new SemaphoreSlim(1); public async Task MethodA() { await semaphore.WaitAsync(); await DoSomeStuff(); semaphore.Release(); } public async Task MethodB() { bool success = await semaphore.WaitAsync(1); if (!success) return; await DoSomeStuff(); await Task.Delay(TimeSpan.FromSeconds(5)); semaphore.Release(); } }
I would consider putting all that in try..catch..finally block and release the semaphore in the finally block, but i'm trying to keep it simple while you can add that yourself.
Unit testing:
This is not straight forward to test. Taking threads into account, you might need to repeat the test multiple times to reach a case of failure. You might need to introduce an overload for method A that waits for some times, which might prove that method B is waiting for it. Here is the test. To test the case of failure, change new SemaphoreSlim(1); to new SemaphoreSlim(2); and the test would fail because MethodB would start before MethodA ends.
[TestMethod] public async Task TestingMyClassThreadSync() { int repeatTimes = 100; int counter = 0; while (counter++ <= repeatTimes) { MyClass myClass = new MyClass(); Task tA = myClass.MethodA(); Task tB = myClass.MethodB(); Task finishedTask = await Task.WhenAny(tA, tB); bool bFinishedBeforeA = finishedTask == tA; if (bFinishedBeforeA) Assert.Fail(); } }
I would introduce an overload:
public async Task MethodA(long waitMilliseconds = 0) { await semaphore.WaitAsync(); await DoSomeStuff(); await Task.Delay(waitMilliseconds); semaphore.Release(); }
Then Call it from unit testing as MethodA(5000);
WaitForBToFinish? Can you show that please, it seems to be a critical method. + How are you callingMethodAandMethodB?lockinstead?awaitin alock