Skip to content

Commit 1c3f210

Browse files
committed
Start threads only after calling read and write on ThreadedGzip
This patch reverts daemon threads, and postpones the launch of threads until calling `read` / `write` on `ThreadedGzipReader` / `ThreadedGzipWriter`. This is supposed to fix #53. Signed-off-by: y5c4l3 <[email protected]>
1 parent 050fb00 commit 1c3f210

File tree

2 files changed

+30
-20
lines changed

2 files changed

+30
-20
lines changed

src/zlib_ng/gzip_ng_threaded.py

+29-20
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,9 @@ def __init__(self, filename, queue_size=2, block_size=1024 * 1024):
9898
self.exception = None
9999
self.buffer = io.BytesIO()
100100
self.block_size = block_size
101-
# Using a daemon thread prevents programs freezing on error.
102-
self.worker = threading.Thread(target=self._decompress, daemon=True)
101+
self.worker = threading.Thread(target=self._decompress)
103102
self._closed = False
104-
self.running = True
105-
self.worker.start()
103+
self.running = False
106104

107105
def _check_closed(self, msg=None):
108106
if self._closed:
@@ -126,8 +124,19 @@ def _decompress(self):
126124
except queue.Full:
127125
pass
128126

127+
def _start(self):
128+
if not self.running:
129+
self.running = True
130+
self.worker.start()
131+
132+
def _stop(self):
133+
if self.running:
134+
self.running = False
135+
self.worker.join()
136+
129137
def readinto(self, b):
130138
self._check_closed()
139+
self._start()
131140
result = self.buffer.readinto(b)
132141
if result == 0:
133142
while True:
@@ -155,8 +164,7 @@ def tell(self) -> int:
155164
def close(self) -> None:
156165
if self._closed:
157166
return
158-
self.running = False
159-
self.worker.join()
167+
self._stop()
160168
self.fileobj.close()
161169
if self.closefd:
162170
self.raw.close()
@@ -232,18 +240,17 @@ def __init__(self,
232240
queue.Queue(queue_size) for _ in range(threads)]
233241
self.output_queues: List[queue.Queue[Tuple[bytes, int, int]]] = [
234242
queue.Queue(queue_size) for _ in range(threads)]
235-
# Using daemon threads prevents a program freezing on error.
236-
self.output_worker = threading.Thread(target=self._write, daemon=True)
243+
self.output_worker = threading.Thread(target=self._write)
237244
self.compression_workers = [
238-
threading.Thread(target=self._compress, args=(i,), daemon=True)
245+
threading.Thread(target=self._compress, args=(i,))
239246
for i in range(threads)
240247
]
241248
elif threads == 1:
242249
self.input_queues = [queue.Queue(queue_size)]
243250
self.output_queues = []
244251
self.compression_workers = []
245252
self.output_worker = threading.Thread(
246-
target=self._compress_and_write, daemon=True)
253+
target=self._compress_and_write)
247254
else:
248255
raise ValueError(f"threads should be at least 1, got {threads}")
249256
self.threads = threads
@@ -254,7 +261,6 @@ def __init__(self,
254261
self.raw, self.closefd = open_as_binary_stream(filename, mode)
255262
self._closed = False
256263
self._write_gzip_header()
257-
self.start()
258264

259265
def _check_closed(self, msg=None):
260266
if self._closed:
@@ -277,21 +283,24 @@ def _write_gzip_header(self):
277283
self.raw.write(struct.pack(
278284
"BBBBIBB", magic1, magic2, method, flags, mtime, os, xfl))
279285

280-
def start(self):
281-
self.running = True
282-
self.output_worker.start()
283-
for worker in self.compression_workers:
284-
worker.start()
286+
def _start(self):
287+
if not self.running:
288+
self.running = True
289+
self.output_worker.start()
290+
for worker in self.compression_workers:
291+
worker.start()
285292

286293
def stop(self):
287294
"""Stop, but do not care for remaining work"""
288-
self.running = False
289-
for worker in self.compression_workers:
290-
worker.join()
291-
self.output_worker.join()
295+
if self.running:
296+
self.running = False
297+
for worker in self.compression_workers:
298+
worker.join()
299+
self.output_worker.join()
292300

293301
def write(self, b) -> int:
294302
self._check_closed()
303+
self._start()
295304
with self.lock:
296305
if self.exception:
297306
raise self.exception

tests/test_gzip_ng_threaded.py

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def test_threaded_write_error(threads):
105105
threads=threads, block_size=8 * 1024)
106106
# Bypass the write method which should not allow blocks larger than
107107
# block_size.
108+
f._start()
108109
f.input_queues[0].put((os.urandom(1024 * 64), b""))
109110
with pytest.raises(OverflowError) as error:
110111
f.close()

0 commit comments

Comments
 (0)