Prior to that date, none of the interrupt-safe task synchronization and signaling mechanisms known to computer scientists was efficiently scalable for use by more than two tasks. Dijkstra's revolutionary, safe-and-scalable Semaphore was applied in bothcritical section protection andsignaling. And thus the confusion began.
Sometimes it is useful to allow more than one worker access to a resource at a time, while still limiting the overall number. For example, a connection pool might support a fixed number of simultaneous connections, or a network application might support a fixed number of concurrent downloads. A Semaphore is one way to manage those connections.
importloggingimportrandomimportthreadingimporttimelogging.basicConfig(level=logging.DEBUG,format='%(asctime)s (%(threadName)-2s) %(message)s',)classActivePool(object):def__init__(self):super(ActivePool,self).__init__()self.active=[]self.lock=threading.Lock()defmakeActive(self,name):withself.lock:self.active.append(name)logging.debug('Running: %s',self.active)defmakeInactive(self,name):withself.lock:self.active.remove(name)logging.debug('Running: %s',self.active)defworker(s,pool):logging.debug('Waiting to join the pool')withs:name=threading.currentThread().getName()pool.makeActive(name)time.sleep(0.1)pool.makeInactive(name)pool=ActivePool()s=threading.Semaphore(2)foriinrange(4):t=threading.Thread(target=worker,name=str(i),args=(s,pool))t.start()