import typing as T
import time
import random
from threading import Thread, Semaphore, Lock
TOTAL_SPOTS = 3
class Garage:
def __init__(self) -> None:
self.semaphore = Semaphore(TOTAL_SPOTS)
self.cars_lock = Lock()
self.parked_cars: T.LIST[str] = []
def count_parked_cars(self) -> int:
return len(self.parked_cars)
def enter(self, car_name: str) -> None:
self.semaphore.acquire()
self.cars_lock.acquire()
self.parked_cars.append(car_name)
print(f"{car_name} parked")
self.cars_lock.release()
def exit(self, car_name: str) -> None:
self.cars_lock.acquire()
self.parked_cars.remove(car_name)
print(f"{car_name} leaving")
self.semaphore.release()
self.cars_lock.release()
def park_car(garage: Garage, car_name: str) -> None:
garage.enter(car_name)
time.sleep(random.uniform(1, 2))
garage.exit(car_name)
def test_garage(garage: Garage, number_of_cars: int = 10) -> None:
threads = []
for car_num in range(number_of_cars):
t = Thread(target=park_car,
args=(garage, f"Car #{car_num}"))
threads.append(t)
t.start()
for thread in threads:
thread.join()
if __name__ == "__main__":
number_of_cars = 10
garage = Garage()
test_garage(garage, number_of_cars)
print("Number of parked cars after a busy day:")
print(f"Actual: {garage.count_parked_cars()}\nExpected: 0")
e$ python3 semaphore.py
Car #0 parked
Car #1 parked
Car #2 parked
Car #1 leaving
Car #3 parked
Car #2 leaving
Car #4 parked
Car #0 leaving
Car #5 parked
Car #3 leaving
Car #6 parked
Car #4 leaving
Car #7 parked
Car #5 leaving
Car #8 parked
Car #6 leaving
Car #9 parked
Car #7 leaving
Car #8 leaving
Car #9 leaving
Number of parked cars after a busy day:
Actual: 0
Expected: 0