Search code examples
pythonmultithreading

How to use "threading" in python in an unblocking way?


I have a complete "working" python code which is supposed to contain two threads which run simultaneously, which populate some lists in a dict, and when the user presses CRTL-C these two threads should be stopped and some output from both threads should be written to a file:

import sys
import time
import threading
import signal
from functools import partial

messages = {}
lock = threading.Lock()

class Handler:
    def __init__(self, port):
        self.port = port

    def run(self):
        while True:
            time.sleep(1)
            with lock:
                messages[self.port].append(time.time())


def signal_handler(filename, sig, frame):
    with lock:
        with open(filename, "w") as fileout:
                json.dump(messages, fileout)
    sys.exit(0)


output = "test.out"
signal.signal(signal.SIGINT, partial(signal_handler, output))
for port in [1,2]:
    messages[port] = []
    handler = Handler(port)
    print("debug1")
    t = threading.Thread(target=handler.run())
    print("debug2")
    t.daemon = True
    t.start()
    threads.append(t)

# Keep the main thread running, waiting for CTRL-C
try:
    while True:
        pass
except KeyboardInterrupt:
    signal_handler(output, signal.SIGINT, None)

However, this code blocks execution after the first debug1 has been printed. How to "unblock" this line so the two threads are started until the user presses CRTL-C (and the output is saved to a file)?

...The above code is just a template of a more complicated code that actually does something useful...


Solution

  • Apart from various typos (forgotten import json and threads=[]) the main problem is in t = threading.Thread(target=handler.run()).

    The target parameter is expected to be a function object, not the result of the call of that function. Here this code immediately calls the never ending function to assign its never coming result to t, actually blocking the main program.

    The solution is just to remove the parens:

    t = threading.Thread(target=handler.run)