0

I'm trying to see how multi thread are working in order to use them in an automation project. I can run the thread but I cannot find a way to exit completely the two threads: the thread restart after each keyboard interupt. Is there a way to exit both thread with a keyboard interupt ?

import thread
from time import sleep

*parameters when starting
temp_c = 32
T_hot = 30
T_cold = 27
interval_temp = 2


def ctrl_fan(temp_c, T_hot,interval_temp):
    while True:
        if temp_c >= T_hot:
            print 'refreshing'
        else:
            print ' fan stopped'
        sleep(interval_temp)

    print 'shutting everything off'


def ctrl_light(temp_c, T_cold,interval_temp):
    while True:
        if temp_c <= T_cold:
            print 'warming'
        else:
            print 'light stopped'
        sleep(interval_temp)

    print 'shutting everything off'


try:
    thread.start_new_thread(ctrl_fan, (temp_c, T_hot,interval_temp, ) )

    sleep(1)

    thread.start_new_thread(ctrl_light, (temp_c, T_cold,interval_temp, ) )
except (KeyboardInterrupt, SystemExit):
    thread.exit()
    print "Error: unable to start thread"
Yoann_R
  • 99
  • 7
  • Just a warning, `temp_c` is being passed by value, so that will never change throughout the lifetime of the thread. – GP89 Nov 07 '14 at 13:57
  • Yes; what I'm planning to do is to add as a thread the reading of temperature and as another one the control of fan and light to control the temperature. I've used a fixed value just to see if it was working. – Yoann_R Nov 07 '14 at 14:07

2 Answers2

1

Sure,

Firstly I'd recommend using the slightly higher level threading module instead of the thread module.

To start a thread with threading use the following

import threading
t = threading.Thread(target=ctrl_fan, args=(temp_c, T_hot, interval_temp))
t.start()

There's a few things you'll need to do to get the program to exit with a Ctrl-C interupt.

Firstly you will want to set the threads to be daemon, so that they allow the program to exit when the main thread exits (t.daemon = True)

You will also want the main thread to wait on the completion of the threads, you can use t.join() to do this. However this wont raise out a KeyboardInterrupt exception until the thread finishes, there is a work around for this though

while t.is_alive():
    t.join(1)

Providing a timeout value gets around this.

I'd be tempted to pull this together into a subclass, to get the behaviour you want

import threading

class CustomThread(threading.Thread):
    def __init__(self, *args, **kwargs):
        threading.Thread.__init__(self, *args, **kwargs)
        self.daemon = True

    def join(self, timeout=None):
        if timeout is None:
            while self.is_alive():
                threading.Thread.join(self, 10)
        else:
            return threading.Thread.join(self, timeout)

t1 = CustomThread(target=ctrl_fan, args=(temp_c, T_hot, interval_temp))
t1.start()

t2 = CustomThread(target=ctrl_light, args=(temp_c, T_cold, interval_temp))
t2.start()

t1.join()
t2.join()
GP89
  • 6,600
  • 4
  • 36
  • 64
  • I'm missing something. Do I need to add a except keyboard interupt into my functions to stop the threads? – Yoann_R Nov 07 '14 at 14:10
  • @Yoann_R No, this should work. The main thread will die with the unhandled `KeyboardInterrupt` exception, and the threads will then in turn die as well because they were set to be `daemon`. – GP89 Nov 07 '14 at 14:12
  • It's not working on my side. At first it displays:Traceback (most recent call last): File "C:\Users\test", line 50, in t1.join() File "C:\Users", line 38, in join threading.Thread.join(self, 10) KeyboardInterrupt and after that it continues printing if I redo a CTRL c it just displays a KeyboardInterrupt – Yoann_R Nov 07 '14 at 14:24
  • @Yoann_R Hmm odd, seems to be working for me. Just to be sure- this is what I'm running: http://pastebin.com/N6gYKgjQ – GP89 Nov 07 '14 at 14:35
  • I've tried, it's the same result: not ending the threads. I'm running python 2.7.3 on windows. @dcexcal documentation from what I've understood; I have to look at lock. – Yoann_R Nov 07 '14 at 14:43
  • I think this must be a windows quirk that I'm not aware of. I think @dcexcal has nailed it though - on windows it seems as if the behaviour is arbitrary. Sorry I can't help more! – GP89 Nov 07 '14 at 15:01
1

The explanation is, again, in the documentation (https://docs.python.org/2/library/thread.html) :

Threads interact strangely with interrupts: the KeyboardInterrupt exception will be received by an arbitrary thread. (When the signal module is available, interrupts always go to the main thread.)

You'd certainly find answers in https://stackoverflow.com/, like :

Propagate system call interruptions in threads

Community
  • 1
  • 1
dcexcal
  • 197
  • 7