Overview:
- A semaphore is a synchronization construct.
- Semaphore provides threads with synchronized access to a limited number of resources.
- A semaphore is just a variable. The variable reflects the number of currently available resources. For example, a parking lot with a display of number of available slots on a specific level of a shopping mall is a semaphore.
- The value of semaphore cannot go less than zero and greater then the total number of the available resources.
- The semaphore is associated with two operations – acquire and release.
- When one of the resources synchronized by a semaphore is "acquired" by a thread, the value of the semaphore is decremented.
- When one of the resources synchronized by a semaphore is "released" by a thread the value of the semaphore is incremented.
- The Dutch computer scientist Edsger Dijkstra invented the concept of semaphore.
- Dijkstra named the two operations on a semaphore acquire and release as p and v using the first letter of the Dutch words proberen and vehogen.
- The word proberen means test and vehogen means increment in Dutch.
Semaphores in Python:
- The Semaphore class of the Python threading module implements the concept of semaphore.
- It has a constructor and two methods acquire() and release().
- The acquire() method decreases the semaphore count if the count is greater than zero. Else it blocks till the count is greater than zero.
- The release() method increases the semaphore count and wakes up one of the threads waiting on the semaphore.
Example:
# An example python program using semaphore provided by the python threading module import threading import time
parkRequests = 0 removeRequests = 0
parked = 0 removed = 0
parkedLock = threading.Lock() removedLock = threading.Lock()
availbleParkings = threading.Semaphore(10)
def ParkCar(): availbleParkings.acquire() global parkedLock parkedLock.acquire()
global parked parked = parked+1 parkedLock.release()
print("Parked: %d"%(parked))
def RemoveCar(): availbleParkings.release() global removedLock removedLock.acquire()
global removed removed = removed+1 removedLock.release() print("Removed: %d"%(removed))
# Thread that simulates the entry of cars into the parking lot def parkingEntry(): # Creates multiple threads inside to simulate cars that are parked while(True): time.sleep(1) incomingCar = threading.Thread(target=ParkCar) incomingCar.start()
global parkRequests parkRequests = parkRequests+1 print("Parking Requests: %d"%(parkRequests))
# Thread that simulates the exit of cars from the parking lot def parkingExit(): # Creates multiple threads inside to simulate cars taken out from the parking lot while(True): time.sleep(3) outgoingCar = threading.Thread(target=RemoveCar) outgoingCar.start()
global removeRequests removeRequests = removeRequests+1 print("Remove Requests: %d"%(removeRequests))
# Start the parking eco-system parkingEntryThread = threading.Thread(target=parkingEntry) parkingExitThread = threading.Thread(target=parkingExit)
parkingEntryThread.start() parkingExitThread.start() |
Output:
Parked: 14 Parking Requests: 14 Removed: 5 Remove Requests: 5 Parked: 15 Parking Requests: 15 Parking Requests: 16 Parking Requests: 17 Removed: 6 Remove Requests: 6 Parked: 16 Parking Requests: 18 Parking Requests: 19 Parking Requests: 20 Removed: 7 Remove Requests: 7 Parked: 17 Parking Requests: 21 Parking Requests: 22 Parking Requests: 23 Removed: 8 Parked: 18 Remove Requests: 8 Parking Requests: 24 |