Ramon Melo
Ramon Melo

Reputation: 270

Why does signal.pause() stop sockets from breaking?

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

Answers (1)

spectras
spectras

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

Related Questions