Reputation: 270
I am working with sockets using Python 3.5 and the multiprocessing
module and running into an unexpected behavior. My program is essentially a couple of threads running until a certain message is received by the client telling it to stop.
If I execute it like this, I get a BrokenPipeError
that breaks the program, despite the while True
loop and the except
block.
#!/usr/bin/env python3
import signal
import traceback
from multiprocessing.dummy import Pool
from process import Process
def main():
while True:
try:
# a Process has a couple threads
process = Process()
listener_pool = Pool(processes=1)
sender_pool = Pool(processes=1)
# blocking socket client that runs forever
listener_pool.apply_async(process.listener_thread.run, ())
# blocking socket server that runs forever
sender_pool.apply_async(process.sender_thread.run, ())
return 0
except BrokenPipeError:
traceback.print_exc()
# closing connections
process.emitter_thread.socket.close()
process.listener_thread.socket.close()
if __name__ == '__main__':
main()
However, when I added a signal.pause()
right before returning, not only the code runs as intended, but also no BrokenPipeError
is raised at any time.
#!/usr/bin/env python3
import signal
import traceback
from multiprocessing.dummy import Pool
from process import Process
def main():
while True:
try:
# a Process has a couple threads
process = Process()
listener_pool = Pool(processes=1)
sender_pool = Pool(processes=1)
# blocking socket client that runs forever
listener_pool.apply_async(process.listener_thread.run, ())
# blocking socket server that runs forever
sender_pool.apply_async(process.sender_thread.run, ())
signal.pause()
return 0
except BrokenPipeError:
traceback.print_exc()
# closing connections
process.emitter_thread.socket.close()
process.listener_thread.socket.close()
if __name__ == '__main__':
main()
According to the docs, signals can only be handled by the main thread, but both sockets are being handled by secondary threads. What does signal.pause()
do to prevent the sockets from breaking, when they are not even being called in the same context?
Upvotes: 2
Views: 655
Reputation: 13552
The apply_async
, as its name suggests returns immediately. Therefore in the first version of your program, the main thread exits right as it starts the child threads (dummy processes are just threads using the multiprocessing api).
Therefore the main thread has exited the try
block long before the exception happens.
In the second case, signal.pause()
forces the main thread to wait in the try
block, where it will catch the exception.
Do note this is a fragile solution though, as receiving any signal will make signal.pause()
resume and the main thread exit.
Upvotes: 2