now assume that the barber method starts running first:
it'll check if there are any customer is ready it'll find that there is no any customer is ready yet, so it will wait.
now the customer method will run and it'll check the free chairs, and upon to you comment that free_chairs will be initialized to N,
so it'll not wait, and then we will increment the customer_ready by one and wake it up (customer_ready), and then we will continue and check if the barber_ready not zero but unfortunately it's zero so we will wait.
and now the schedular will choose the barber method, and the customer_ready we already wake it up when we were on customer method and increment it by one so the value of customer_ready will be zero now and we'll return from wait and continue in the method.
now we will post free chairs(for the next iteration) and post barber_ready to one.
now we'll come back to the customer method and we stop on line 13 so we already increment it by line 7, and we will get_hair cut so we finish.
and if you want to try for another iteration, by coming back to the barber method we'll again find that customer_ready is zero again and retry the same scenario.
if you want to trail on another scenario by starting with the customer, starting with line 11 you'll not wait because the number of free chairs is N, so continue, incrementing customer_ready by line 12, and then by (line 13), we'll wait for barber_ready to increment.
so coming back to the barber, you'll find the customer_ready is already incremented by line 12, so continue, incrementing free chairs and then incrementing the barber_ready, when we come back to the customer we'll return from waiting(line 13) because we already increment it by line 7 and continue.
these are the two scenarios, and we find why there's no racing here.