Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 1 | # A multi-producer, multi-consumer queue. |
| 2 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 3 | # define this exception to be compatible with Python 1.5's class |
| 4 | # exceptions, but also when -X option is used. |
| 5 | try: |
| 6 | class Empty(Exception): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 7 | pass |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 8 | except TypeError: |
| 9 | # string based exceptions |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 10 | Empty = 'Queue.Empty' # Exception raised by get_nowait() |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 11 | |
| 12 | class Queue: |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 13 | def __init__(self, maxsize): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 14 | """Initialize a queue object with a given maximum size. |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 15 | |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 16 | If maxsize is <= 0, the queue size is infinite. |
| 17 | """ |
| 18 | import thread |
| 19 | self._init(maxsize) |
| 20 | self.mutex = thread.allocate_lock() |
| 21 | self.esema = thread.allocate_lock() |
| 22 | self.esema.acquire_lock() |
| 23 | self.fsema = thread.allocate_lock() |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 24 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 25 | def qsize(self): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 26 | """Returns the approximate size of the queue (not reliable!).""" |
| 27 | self.mutex.acquire_lock() |
| 28 | n = self._qsize() |
| 29 | self.mutex.release_lock() |
| 30 | return n |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 31 | |
| 32 | def empty(self): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 33 | """Returns 1 if the queue is empty, 0 otherwise (not reliable!).""" |
| 34 | self.mutex.acquire_lock() |
| 35 | n = self._empty() |
| 36 | self.mutex.release_lock() |
| 37 | return n |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 38 | |
| 39 | def full(self): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 40 | """Returns 1 if the queue is full, 0 otherwise (not reliable!).""" |
| 41 | self.mutex.acquire_lock() |
| 42 | n = self._full() |
| 43 | self.mutex.release_lock() |
| 44 | return n |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 45 | |
| 46 | def put(self, item): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 47 | """Put an item into the queue.""" |
| 48 | self.fsema.acquire_lock() |
| 49 | self.mutex.acquire_lock() |
| 50 | was_empty = self._empty() |
| 51 | self._put(item) |
| 52 | if was_empty: |
| 53 | self.esema.release_lock() |
| 54 | if not self._full(): |
| 55 | self.fsema.release_lock() |
| 56 | self.mutex.release_lock() |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 57 | |
| 58 | def get(self): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 59 | """Gets and returns an item from the queue. |
| 60 | This method blocks if necessary until an item is available. |
| 61 | """ |
| 62 | self.esema.acquire_lock() |
| 63 | self.mutex.acquire_lock() |
| 64 | was_full = self._full() |
| 65 | item = self._get() |
| 66 | if was_full: |
| 67 | self.fsema.release_lock() |
| 68 | if not self._empty(): |
| 69 | self.esema.release_lock() |
| 70 | self.mutex.release_lock() |
| 71 | return item |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 72 | |
| 73 | # Get an item from the queue if one is immediately available, |
| 74 | # raise Empty if the queue is empty or temporarily unavailable |
| 75 | def get_nowait(self): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 76 | """Gets and returns an item from the queue. |
| 77 | Only gets an item if one is immediately available, Otherwise |
| 78 | this raises the Empty exception if the queue is empty or |
| 79 | temporarily unavailable. |
| 80 | """ |
| 81 | locked = self.esema.acquire_lock(0) |
| 82 | self.mutex.acquire_lock() |
| 83 | if self._empty(): |
| 84 | # The queue is empty -- we can't have esema |
| 85 | self.mutex.release_lock() |
| 86 | raise Empty |
| 87 | if not locked: |
| 88 | locked = self.esema.acquire_lock(0) |
| 89 | if not locked: |
| 90 | # Somebody else has esema |
| 91 | # but we have mutex -- |
| 92 | # go out of their way |
| 93 | self.mutex.release_lock() |
| 94 | raise Empty |
| 95 | was_full = self._full() |
| 96 | item = self._get() |
| 97 | if was_full: |
| 98 | self.fsema.release_lock() |
| 99 | if not self._empty(): |
| 100 | self.esema.release_lock() |
| 101 | self.mutex.release_lock() |
| 102 | return item |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 103 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 104 | # XXX Need to define put_nowait() as well. |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 105 | |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 106 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 107 | # Override these methods to implement other queue organizations |
| 108 | # (e.g. stack or priority queue). |
| 109 | # These will only be called with appropriate locks held |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 110 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 111 | # Initialize the queue representation |
| 112 | def _init(self, maxsize): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 113 | self.maxsize = maxsize |
| 114 | self.queue = [] |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 115 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 116 | def _qsize(self): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 117 | return len(self.queue) |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 118 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 119 | # Check wheter the queue is empty |
| 120 | def _empty(self): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 121 | return not self.queue |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 122 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 123 | # Check whether the queue is full |
| 124 | def _full(self): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 125 | return self.maxsize > 0 and len(self.queue) == self.maxsize |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 126 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 127 | # Put a new item in the queue |
| 128 | def _put(self, item): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 129 | self.queue.append(item) |
Guido van Rossum | 5c97167 | 1996-07-22 15:23:25 +0000 | [diff] [blame] | 130 | |
Guido van Rossum | 0b23348 | 1997-11-26 15:44:34 +0000 | [diff] [blame] | 131 | # Get an item from the queue |
| 132 | def _get(self): |
Guido van Rossum | 548703a | 1998-03-26 22:14:20 +0000 | [diff] [blame] | 133 | item = self.queue[0] |
| 134 | del self.queue[0] |
| 135 | return item |