@@ -33,7 +33,6 @@ class ShutDown(Exception):
3333_queue_shutdown = "shutdown"
3434_queue_shutdown_immediate = "shutdown-immediate"
3535
36-
3736class Queue :
3837 '''Create a queue object with a given maximum size.
3938
@@ -63,7 +62,7 @@ def __init__(self, maxsize=0):
6362 self .all_tasks_done = threading .Condition (self .mutex )
6463 self .unfinished_tasks = 0
6564
66- # Queue shut-down state
65+ # Queue shutdown state
6766 self .shutdown_state = _queue_alive
6867
6968 def task_done (self ):
@@ -79,8 +78,12 @@ def task_done(self):
7978
8079 Raises a ValueError if called more times than there were items
8180 placed in the queue.
81+
82+ Raises ShutDown if the queue has been shut down immediately.
8283 '''
8384 with self .all_tasks_done :
85+ if self ._is_shutdown_immediate ():
86+ raise ShutDown
8487 unfinished = self .unfinished_tasks - 1
8588 if unfinished <= 0 :
8689 if unfinished < 0 :
@@ -96,12 +99,16 @@ def join(self):
9699 to indicate the item was retrieved and all work on it is complete.
97100
98101 When the count of unfinished tasks drops to zero, join() unblocks.
102+
103+ Raises ShutDown if the queue has been shut down immediately.
99104 '''
100105 with self .all_tasks_done :
106+ if self ._is_shutdown_immediate ():
107+ raise ShutDown
101108 while self .unfinished_tasks :
102- if self .shutdown_state == _queue_shutdown_immediate :
103- return
104109 self .all_tasks_done .wait ()
110+ if self ._is_shutdown_immediate ():
111+ raise ShutDown
105112
106113 def qsize (self ):
107114 '''Return the approximate size of the queue (not reliable!).'''
@@ -143,18 +150,20 @@ def put(self, item, block=True, timeout=None):
143150 Otherwise ('block' is false), put an item on the queue if a free slot
144151 is immediately available, else raise the Full exception ('timeout'
145152 is ignored in that case).
153+
154+ Raises ShutDown if the queue has been shut down.
146155 '''
147- if self .shutdown_state != _queue_alive :
148- raise ShutDown
149156 with self .not_full :
157+ if not self ._is_alive ():
158+ raise ShutDown
150159 if self .maxsize > 0 :
151160 if not block :
152161 if self ._qsize () >= self .maxsize :
153162 raise Full
154163 elif timeout is None :
155164 while self ._qsize () >= self .maxsize :
156165 self .not_full .wait ()
157- if self .shutdown_state != _queue_alive :
166+ if not self ._is_alive () :
158167 raise ShutDown
159168 elif timeout < 0 :
160169 raise ValueError ("'timeout' must be a non-negative number" )
@@ -165,7 +174,7 @@ def put(self, item, block=True, timeout=None):
165174 if remaining <= 0.0 :
166175 raise Full
167176 self .not_full .wait (remaining )
168- if self .shutdown_state != _queue_alive :
177+ if not self ._is_alive () :
169178 raise ShutDown
170179 self ._put (item )
171180 self .unfinished_tasks += 1
@@ -181,37 +190,33 @@ def get(self, block=True, timeout=None):
181190 Otherwise ('block' is false), return an item if one is immediately
182191 available, else raise the Empty exception ('timeout' is ignored
183192 in that case).
193+
194+ Raises ShutDown if the queue has been shut down and is empty,
195+ or if the queue has been shut down immediately.
184196 '''
185- if self .shutdown_state == _queue_shutdown_immediate :
186- raise ShutDown
187197 with self .not_empty :
198+ if self ._is_shutdown_immediate () or \
199+ (self ._is_shutdown () and not self ._qsize ()):
200+ raise ShutDown
188201 if not block :
189202 if not self ._qsize ():
190- if self .shutdown_state != _queue_alive :
191- raise ShutDown
192203 raise Empty
193204 elif timeout is None :
194205 while not self ._qsize ():
195- if self .shutdown_state != _queue_alive :
196- raise ShutDown
197206 self .not_empty .wait ()
198- if self .shutdown_state != _queue_alive :
207+ if self ._is_shutdown_immediate () :
199208 raise ShutDown
200209 elif timeout < 0 :
201210 raise ValueError ("'timeout' must be a non-negative number" )
202211 else :
203212 endtime = time () + timeout
204213 while not self ._qsize ():
205- if self .shutdown_state != _queue_alive :
206- raise ShutDown
207214 remaining = endtime - time ()
208215 if remaining <= 0.0 :
209216 raise Empty
210217 self .not_empty .wait (remaining )
211- if self .shutdown_state != _queue_alive :
218+ if self ._is_shutdown_immediate () :
212219 raise ShutDown
213- if self .shutdown_state == _queue_shutdown_immediate :
214- raise ShutDown
215220 item = self ._get ()
216221 self .not_full .notify ()
217222 return item
@@ -242,14 +247,33 @@ def shutdown(self, immediate=False):
242247 and join() if 'immediate'. The ShutDown exception is raised.
243248 '''
244249 with self .mutex :
250+ if self ._is_shutdown_immediate ():
251+ return
245252 if immediate :
246- self .shutdown_state = _queue_shutdown_immediate
253+ self ._set_shutdown_immediate ()
247254 self .not_empty .notify_all ()
255+ # release all blocked threads in `join()`
248256 self .all_tasks_done .notify_all ()
249257 else :
250- self .shutdown_state = _queue_shutdown
258+ self ._set_shutdown ()
251259 self .not_full .notify_all ()
252260
261+ def _is_alive (self ):
262+ return self .shutdown_state == _queue_alive
263+
264+ def _is_shutdown (self ):
265+ return self .shutdown_state == _queue_shutdown
266+
267+ def _is_shutdown_immediate (self ):
268+ return self .shutdown_state == _queue_shutdown_immediate
269+
270+ def _set_shutdown (self ):
271+ self .shutdown_state = _queue_shutdown
272+
273+ def _set_shutdown_immediate (self ):
274+ self .shutdown_state = _queue_shutdown_immediate
275+
276+
253277 # Override these methods to implement other queue organizations
254278 # (e.g. stack or priority queue).
255279 # These will only be called with appropriate locks held
0 commit comments