Two people, one last seat
You have done this today
You are booking a film. One seat is left and so is someone else, and you both tap Book at the same moment.
What happens behind the screen
Without a rule, both payments could go through, and one person would arrive to find someone in their seat. Two ideas prevent that: a queue, and a lock with a deadline.
Step through what happens to the two requests.
Two people tap Book on the last seat at the same moment.
The idea in plain words
A queue puts requests in a line, first in, first out. A lock, also called mutual exclusion, lets only one request change the seat at a time. The lock carries a deadline so an abandoned seat is released.
Checking 'is it free' and writing 'lock it' must happen as one step. If they are two steps, two requests can slip between them. That gap is called a race condition. Stacks appear in the undo path: cancelling reverses steps last in, first out.
A seat hold that expires
import time
from threading import Lock
HOLD_SECONDS = 300
holds = {} # seat -> (user, expires_at)
guard = Lock()
def try_hold(seat, user):
with guard: # check and write happen as one step
now = time.time()
owner = holds.get(seat)
if owner and owner[1] > now and owner[0] != user:
return False # someone else holds it and it has not expired
holds[seat] = (user, now + HOLD_SECONDS)
return TrueIf an interviewer asks
"How would you stop two users booking the same seat?"
You could say
I would make the check and the reservation a single atomic step, using a lock or a database transaction, so no second request can slip in between. The reservation would carry an expiry so abandoned seats are released. Under load I would queue requests per seat so they are handled in order.
Check yourself
Why must 'check if free' and 'lock it' happen as one step?
Why does a hold need a deadline?
Was this clear?
Up next
Why a film is cut into small pieces
How a two-hour film starts playing in a second.