@@ -33,7 +33,6 @@ class ShutDown(Exception):
33
33
_queue_shutdown = "shutdown"
34
34
_queue_shutdown_immediate = "shutdown-immediate"
35
35
36
-
37
36
class Queue :
38
37
'''Create a queue object with a given maximum size.
39
38
@@ -63,7 +62,7 @@ def __init__(self, maxsize=0):
63
62
self .all_tasks_done = threading .Condition (self .mutex )
64
63
self .unfinished_tasks = 0
65
64
66
- # Queue shut-down state
65
+ # Queue shutdown state
67
66
self .shutdown_state = _queue_alive
68
67
69
68
def task_done (self ):
@@ -79,8 +78,12 @@ def task_done(self):
79
78
80
79
Raises a ValueError if called more times than there were items
81
80
placed in the queue.
81
+
82
+ Raises ShutDown if the queue has been shut down immediately.
82
83
'''
83
84
with self .all_tasks_done :
85
+ if self ._is_shutdown_immediate ():
86
+ raise ShutDown
84
87
unfinished = self .unfinished_tasks - 1
85
88
if unfinished <= 0 :
86
89
if unfinished < 0 :
@@ -96,12 +99,16 @@ def join(self):
96
99
to indicate the item was retrieved and all work on it is complete.
97
100
98
101
When the count of unfinished tasks drops to zero, join() unblocks.
102
+
103
+ Raises ShutDown if the queue has been shut down immediately.
99
104
'''
100
105
with self .all_tasks_done :
106
+ if self ._is_shutdown_immediate ():
107
+ raise ShutDown
101
108
while self .unfinished_tasks :
102
- if self .shutdown_state == _queue_shutdown_immediate :
103
- return
104
109
self .all_tasks_done .wait ()
110
+ if self ._is_shutdown_immediate ():
111
+ raise ShutDown
105
112
106
113
def qsize (self ):
107
114
'''Return the approximate size of the queue (not reliable!).'''
@@ -143,18 +150,20 @@ def put(self, item, block=True, timeout=None):
143
150
Otherwise ('block' is false), put an item on the queue if a free slot
144
151
is immediately available, else raise the Full exception ('timeout'
145
152
is ignored in that case).
153
+
154
+ Raises ShutDown if the queue has been shut down.
146
155
'''
147
- if self .shutdown_state != _queue_alive :
148
- raise ShutDown
149
156
with self .not_full :
157
+ if not self ._is_alive ():
158
+ raise ShutDown
150
159
if self .maxsize > 0 :
151
160
if not block :
152
161
if self ._qsize () >= self .maxsize :
153
162
raise Full
154
163
elif timeout is None :
155
164
while self ._qsize () >= self .maxsize :
156
165
self .not_full .wait ()
157
- if self .shutdown_state != _queue_alive :
166
+ if not self ._is_alive () :
158
167
raise ShutDown
159
168
elif timeout < 0 :
160
169
raise ValueError ("'timeout' must be a non-negative number" )
@@ -165,7 +174,7 @@ def put(self, item, block=True, timeout=None):
165
174
if remaining <= 0.0 :
166
175
raise Full
167
176
self .not_full .wait (remaining )
168
- if self .shutdown_state != _queue_alive :
177
+ if not self ._is_alive () :
169
178
raise ShutDown
170
179
self ._put (item )
171
180
self .unfinished_tasks += 1
@@ -181,37 +190,33 @@ def get(self, block=True, timeout=None):
181
190
Otherwise ('block' is false), return an item if one is immediately
182
191
available, else raise the Empty exception ('timeout' is ignored
183
192
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.
184
196
'''
185
- if self .shutdown_state == _queue_shutdown_immediate :
186
- raise ShutDown
187
197
with self .not_empty :
198
+ if self ._is_shutdown_immediate () or \
199
+ (self ._is_shutdown () and not self ._qsize ()):
200
+ raise ShutDown
188
201
if not block :
189
202
if not self ._qsize ():
190
- if self .shutdown_state != _queue_alive :
191
- raise ShutDown
192
203
raise Empty
193
204
elif timeout is None :
194
205
while not self ._qsize ():
195
- if self .shutdown_state != _queue_alive :
196
- raise ShutDown
197
206
self .not_empty .wait ()
198
- if self .shutdown_state != _queue_alive :
207
+ if self ._is_shutdown_immediate () :
199
208
raise ShutDown
200
209
elif timeout < 0 :
201
210
raise ValueError ("'timeout' must be a non-negative number" )
202
211
else :
203
212
endtime = time () + timeout
204
213
while not self ._qsize ():
205
- if self .shutdown_state != _queue_alive :
206
- raise ShutDown
207
214
remaining = endtime - time ()
208
215
if remaining <= 0.0 :
209
216
raise Empty
210
217
self .not_empty .wait (remaining )
211
- if self .shutdown_state != _queue_alive :
218
+ if self ._is_shutdown_immediate () :
212
219
raise ShutDown
213
- if self .shutdown_state == _queue_shutdown_immediate :
214
- raise ShutDown
215
220
item = self ._get ()
216
221
self .not_full .notify ()
217
222
return item
@@ -242,14 +247,33 @@ def shutdown(self, immediate=False):
242
247
and join() if 'immediate'. The ShutDown exception is raised.
243
248
'''
244
249
with self .mutex :
250
+ if self ._is_shutdown_immediate ():
251
+ return
245
252
if immediate :
246
- self .shutdown_state = _queue_shutdown_immediate
253
+ self ._set_shutdown_immediate ()
247
254
self .not_empty .notify_all ()
255
+ # release all blocked threads in `join()`
248
256
self .all_tasks_done .notify_all ()
249
257
else :
250
- self .shutdown_state = _queue_shutdown
258
+ self ._set_shutdown ()
251
259
self .not_full .notify_all ()
252
260
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
+
253
277
# Override these methods to implement other queue organizations
254
278
# (e.g. stack or priority queue).
255
279
# These will only be called with appropriate locks held
0 commit comments