I thought that when the wait was called (both in SetRooms () and SetStars ()) a "snapshot" of the hotel instance is created.
Your Hotel class is a reference type. When you use async-wait, your method is converted to a state-machine, and this state machine raises a link to your variable for it. This means that both machine states created point to the same Hotel instance. There is no βsnapshotβ or deep copy of your Hotel ; the compiler does not.
If you want to see what actually happens, you can see what the compiler emits as soon as it converts your async methods:
[AsyncStateMachine(typeof(C.<SetRooms>d__1))] public Task SetRooms(Hotel hotel) { C.<SetRooms>d__1 <SetRooms>d__; <SetRooms>d__.hotel = hotel; <SetRooms>d__.<>t__builder = AsyncTaskMethodBuilder.Create(); <SetRooms>d__.<>1__state = -1; AsyncTaskMethodBuilder <>t__builder = <SetRooms>d__.<>t__builder; <>t__builder.Start<C.<SetRooms>d__1>(ref <SetRooms>d__); return <SetRooms>d__.<>t__builder.Task; } [AsyncStateMachine(typeof(C.<SetStars>d__2))] public Task SetStars(Hotel hotel) { C.<SetStars>d__2 <SetStars>d__; <SetStars>d__.hotel = hotel; <SetStars>d__.<>t__builder = AsyncTaskMethodBuilder.Create(); <SetStars>d__.<>1__state = -1; AsyncTaskMethodBuilder <>t__builder = <SetStars>d__.<>t__builder; <>t__builder.Start<C.<SetStars>d__2>(ref <SetStars>d__); return <SetStars>d__.<>t__builder.Task; }
You can see that both methods raise the Hotel variable to their state.
So, I expected that between the two tasks and the last one to run would be copied back to the hotel giving 0 in one of two properties.
Now that you see what the compiler actually does, you can understand that this is not really a race condition. This is the same instance of Hotel that is changing, with each method setting a different variable.
Side note
You may have written this code as an example to explain your question, but if you are already creating async methods, I would recommend using Task.WhenAll instead of locking Task.WaitAll . This means changing the Run signature to async Task instead of void :
public async Task RunAsync() { var hotel = new Hotel(); await Task.WhenAll(SetRooms(hotel), SetStars(hotel)); Debug.Assert(hotel.NumberOfRooms.Equals(200)); Debug.Assert(hotel.StarRating.Equals(5)); }
source share