"""A multi-producer, multi-consumer stack."""
class Empty(Exception):
"Exception raised by Stack.get(block=0)/get_nowait()."
pass
class Full(Exception):
"Exception raised by Stack.put(block=0)/put_nowait()."
pass
class Stack:
def __init__(self, maxsize=0):
"""Initialize a stack object with a given maximum size.
If maxsize is <= 0, the stack size is infinite.
"""
import thread
self.maxsize = maxsize
self.stack = []
self.mutex = thread.allocate_lock()
self.esema = thread.allocate_lock()
self.esema.acquire()
self.fsema = thread.allocate_lock()
##shortcut name-bindings
self.mutexAcquire = self.mutex.acquire
self.mutexRelease = self.mutex.release
self.fsemaAcquire = self.fsema.acquire
self.fsemaRelease = self.fsema.release
self.esemaAcquire = self.esema.acquire
self.esemaRelease = self.esema.release
self._put = self.stack.append
def qsize(self):
"""Return the approximate size of the stack (not reliable!)."""
self.mutexAcquire()
n = len(self.stack)
self.mutexRelease()
return n
def empty(self):
"""Return 1 if the stack is empty, 0 otherwise (not reliable!)."""
self.mutexAcquire()
n = not self.stack
self.mutexRelease()
return n
def full(self):
"""Return 1 if the stack is full, 0 otherwise (not reliable!)."""
self.mutexAcquire()
n = ( self.maxsize > 0 and len(self.stack) == self.maxsize )
self.mutexRelease()
return n
def put(self, item, block=1):
"""Put an item into the stack.
If optional arg 'block' is 1 (the default), block if
necessary until a free slot is available. Otherwise (block
is 0), put an item on the stack if a free slot is immediately
available, else raise the Full exception.
"""
theStack = self.stack
if block:
self.fsemaAcquire()
elif not self.fsemaAcquire(0):
raise Full
self.mutexAcquire()
was_empty = not theStack # ~= self._empty()
self._put(item)
if was_empty:
self.esemaRelease()
if not (self.maxsize > 0 and len(theStack) == self.maxsize): # ~= not
self._full():
self.fsemaRelease()
self.mutexRelease()
def put_nowait(self, item):
"""Put an item into the stack without blocking.
Only enqueue the item if a free slot is immediately available.
Otherwise raise the Full exception.
"""
return self.put(item, 0)
def get(self, block=1):
"""Remove and return an item from the stack.
If optional arg 'block' is 1 (the default), block if
necessary until an item is available. Otherwise (block is 0),
return an item if one is immediately available, else raise the
Empty exception.
"""
theStack = self.stack
if block:
self.esemaAcquire()
elif not self.esemaAcquire(0):
raise Empty
self.mutexAcquire()
was_full = (self.maxsize > 0 and len(theStack) == self.maxsize) # ~=
self._full()
item = theStack.pop()
if was_full:
self.fsemaRelease()
if theStack: # ~= not self._empty():
self.esemaRelease()
self.mutexRelease()
return item
def get_nowait(self):
"""Remove and return an item from the stack without blocking.
Only get an item if one is immediately available. Otherwise
raise the Empty exception.
"""
return self.get(0)