I quickly wrote this example script for stackoverflow so ignore the functionality aspect of it (my version looks alot better than this), but:
from threading import Thread
from msvcrt import getch #I'm using Windows by the way.
from time import sleep
import sys
def KeyEvent():
while True:
key = getch()
if key.encode('hex') == '03': #^C
y = raw_input("Are you sure you want to quit? (y/n): ").lower()
if y == 'y':
sys.exit(0)
else: pass
def main():
t = 0
while True:
print "The count is {0}".format(t)
t +=1
sleep(1)
if __name__ == "__main__":
mainthread = Thread(target = main)
kev = Thread(target = KeyEvent)
mainthread.daemon = True
kev.daemon = True
mainthread.start()
kev.start()
What this script is supposed to do is run both loops at the same time, one counts up in seconds, while the other checks for ^C. Please don't recommend that I use a different method, because this is an example.
My problem is, that the script just doesn't start. It displays "The count is 0" and exits, but if I comletely omit the .daemon = True parts, the script runs, but it doesn't run sys.exit(0) correctly. How can I make this script run correctly AND exit when prompted?
Threads marked as daemon automatically die when every other non-daemon thread is dead. In your case, the main thread dies just after calling start() on your two daemon threads, bringing the python process with it. That anything gets done in your thread is a matter of luck and timing.
sys.exit(0) does not kill threads other than the main thread. You need a way to signal your threads that it's time to stop. One way to do that is through an Event object.
You shouldn't use getch to try to catch Ctrl+C, try using a signal handler instead:
from threading import Thread
from threading import Event
from time import sleep
import signal
stop = Event()
def handler(signum, frame):
y = raw_input("Are you sure you want to quit? (y/n): ").lower()
if y == 'y':
stop.set()
def main():
t = 0
while not stop.isSet():
print "The count is {0}".format(t)
t +=1
sleep(1)
if __name__ == "__main__":
signal.signal(signal.SIGINT, handler)
mainthread = Thread(target = main)
mainthread.start()
while mainthread.is_alive():
try:
mainthread.join(timeout = 0.1)
except IOError:
pass #Gets thrown when we interrupt the join
You have two problems. First is that your program ends too early. Second is that you try to quit the program in your KeyEvent thread.
Your program terminates early because you didn't hold your main thread. Your main thread ends right after your last statement kev.start() and your daemon threads die with it.
You need a mechanism to hold the main thread infinitively (because you expect the user to type "y" to quit.) There are several ways of doing this. One is add
mainthread.join()
to the end of your code.
Second, sys.exit(0) in your KeyEvent thread obviously can not terminate your whole program. Please find your answer in the following post: Why does sys.exit() not exit when called inside a thread in Python?
Related
I've made a program which has a main thread that spawns many other threads by subclassing the threading.Thread class.
Each such child thread runs an infinite while loop, and inside the loop I check a condition. If the condition is true, I make the thread sleep for 1 second using time.sleep(1) and if it's false, then the thread performs some computation.
The program itself works fine and I've achieved what I wanted to do, my only remaining problem is that I seem unable to stop the threads after my work is done. I want the user to be able to kill all the threads by pressing a button or giving a keyboard interrupt like Ctrl+C.
For this I had tried using the signal module and inserted a conditon in the threads' loops that breaks the loop when the main thread catches a signal but it didn't work for some reason. Can anyone please help with this?
EDIT: This is some of the relevant code snippets:
def sighandler(signal,frame):
BaseThreadClass.stop_flag = True
class BaseThreadClass(threading.Thread):
stop_flag = False
def __init__(self):
threading.Thread.__init__(self)
def run(self,*args):
while True:
if condition:
time.sleep(1)
else:
#do computation and stuff
if BaseThreadClass.stop_flag:
#do cleanup
break
Your basic method does work, but you've still not posted enough code to show the flaw. I added a few lines of code to make it runnable and produced a result like:
$ python3 test.py
thread alive
main alive
thread alive
main alive
^CSignal caught
main alive
thread alive
main alive
main alive
main alive
^CSignal caught
^CSignal caught
main alive
^Z
[2]+ Stopped python3 test.py
$ kill %2
The problem demonstrated above involves the signal handler telling all the threads to exit, except the main thread, which still runs and still catches interrupts. The full source of this variant of the sample snippet is:
import threading, signal, time
def sighandler(signal,frame):
BaseThreadClass.stop_flag = True
print("Signal caught")
class BaseThreadClass(threading.Thread):
stop_flag = False
def __init__(self):
threading.Thread.__init__(self)
def run(self,*args):
while True:
if True:
time.sleep(1)
print("thread alive")
else:
#do computation and stuff
pass
if BaseThreadClass.stop_flag:
#do cleanup
break
signal.signal(signal.SIGINT, sighandler)
t = BaseThreadClass()
t.start()
while True:
time.sleep(1)
print("main alive")
The problem here is that the main thread never checks for the quit condition. But as you never posted what the main thread does, nor how the signal handler is activated, or information regarding whether threads may go a long time without checking the quit condition... I still don't know what went wrong in your program. The signal example shown in the library documentation raises an exception in order to divert the main thread.
Signals are a rather low level concept for this task, however. I took the liberty of writing a somewhat more naïve version of the main thread:
try:
t = BaseThreadClass()
t.start()
while True:
time.sleep(1)
print("main alive")
except KeyboardInterrupt:
BaseThreadClass.stop_flag = True
t.join()
This version catches the exception thrown by the default interrupt handler, signals the thread to stop, and waits for it to do so. It might even be appropriate to change the except clause to a finally, since we could want to clean the threads up on other errors too.
If you want to do this kind of "cooperative" polled-shutdown, you can use a threading.Event to signal:
import threading
import time
def proc1():
while True:
print("1") # payload
time.sleep(1)
# have we been signalled to stop?
if not ev1.wait(0): break
# do any shutdown etc. here
print ("T1 exiting")
ev1 = threading.Event()
ev1.set()
thread1 = threading.Thread(target=proc1)
thread1.start()
time.sleep(3)
# signal thread1 to stop
ev1.clear()
But be aware that if the "payload" does something blocking like network or file IO, that op will not be interrupted. You can do those blocking ops with a timeout, but that obviously will complicate your code.
I'm trying to run a background timer while running other processes. I've used thread.Thread:
import threading
import random
import time
import sys
def timer(limit):
time.sleep(limit)
sys.exit()
def code():
dictionary=['hello','loading','dumb']
word=[]
c=random.choice(dictionary)
answer=c
for x in c:
word.append(x)
y=0
words=''
while y!=len(c):
x=random.choice(word)
word.remove(x)
words=words+x
y+=1
print(words)
guess=input()
if guess==answer:
print('NOICE')
else:
print("NUB")
permit=input('Play Again?')
t1=threading.Thread(target=timer, args=(10,))
t2=threading.Thread(target=code)
t1.start()
t2.start()
That`s all my code. The problem is that when i run it, the timer waits for input before exiting. I want the timer to exit at ten second mark, whether or not input was entered. I thought that threading would make it so that the processes would not have to wait for each other. Help please?
Oh, and I'm only a few days into python, so please keep your explanations simple. Thanks.
When you call sys.exit() in one of your threads, this does not affect the other threads. That is simply the nature of them! All threads are equal.
If you want to make a thread that will terminate when the program exits, it needs to be made into a daemon (think a slave under the master thread).
To do that:
slave_thread.daemon = True
And in your case:
t2.daemon = True
Thus, t2 will be terminated when the main thread exits. Do not confuse this main thread with t1. The main thread will continue executing while there are threads running (t1). But as soon as t1 exits, t2 will be terminated, because it is a daemon.
EDIT 9/15/16: In my original code (still posted below) I tried to use .join() with a function, which is a silly mistake because it can only be used with a thread object. I am trying to
(1) continuously run a thread that gets data and saves it to a file
(2) have a second thread, or incorporate queue, that will stop the program once a user enters a flag (i.e. "stop"). It doesn't interrupt the data gathering/saving thread.
I need help with multithreading. I am trying to run two threads, one that handles data and the second checks for a flag to stop the program.
I learned by trial and error that I can't interrupt a while loop without my computer exploding. Additionally, I have abandoned my GUI code because it made my code too complicated with the mulithreading.
What I want to do is run a thread that gathers data from an Arduino, saves it to a file, and repeats this. The second thread will scan for a flag -- which can be a raw_input? I can't think of anything else that a user can do to stop the data acquisition program.
I greatly appreciate any help on this. Here is my code (much of it is pseudocode, as you can see):
#threading
import thread
import time
global flag
def monitorData():
print "running!"
time.sleep(5)
def stopdata(flag ):
flag = raw_input("enter stop: ")
if flag == "stop":
monitorData.join()
flag = "start"
thread.start_new_thread( monitorData,())
thread.start_new_thread( stopdata,(flag,))
The error I am getting is this when I try entering "stop" in the IDLE.
Unhandled exception in thread started by
Traceback (most recent call last):
File "c:\users\otangu~1\appdata\local\temp\IDLE_rtmp_h_frd5", line 16, in stopdata
AttributeError: 'function' object has no attribute 'join'
Once again I really appreciate any help, I have taught myself Python so far and this is the first huge wall that I've hit.
The error you see is a result of calling join on the function. You need to call join on the thread object. You don't capture a reference to the thread so you have no way to call join anyway. You should join like so.
th1 = thread.start_new_thread( monitorData,())
# later
th1.join()
As for a solution, you can use a Queue to communicate between threads. The queue is used to send a quit message to the worker thread and if the worker does not pick anything up off the queue for a second it runs the code that gathers data from the arduino.
from threading import Thread
from Queue import Queue, Empty
def worker(q):
while True:
try:
item = q.get(block=True, timeout=1)
q.task_done()
if item == "quit":
print("got quit msg in thread")
break
except Empty:
print("empty, do some arduino stuff")
def input_process(q):
while True:
x = raw_input("")
if x == 'q':
print("will quit")
q.put("quit")
break
q = Queue()
t = Thread(target=worker, args=(q,))
t.start()
t2 = Thread(target=input_process, args=(q,))
t2.start()
# waits for the `task_done` function to be called
q.join()
t2.join()
t.join()
It's possibly a bit more code than you hoped for and having to detect the queue is empty with an exception is a little ugly, but this doesn't rely on any global variables and will always exit promptly. That wont be the case with sleep based solutions, which need to wait for any current calls to sleep to finish before resuming execution.
As noted by someone else, you should really be using threading rather than the older thread module and also I would recommend you learn with python 3 and not python 2.
You're looking for something like this:
from threading import Thread
from time import sleep
# "volatile" global shared by threads
active = True
def get_data():
while active:
print "working!"
sleep(3)
def wait_on_user():
global active
raw_input("press enter to stop")
active = False
th1 = Thread(target=get_data)
th1.start()
th2 = Thread(target=wait_on_user)
th2.start()
th1.join()
th2.join()
You made a few obvious and a few less obvious mistakes in your code. First, join is called on a thread object, not a function. Similarly, join doesn't kill a thread, it waits for the thread to finish. A thread finishes when it has no more code to execute. If you want a thread to run until some flag is set, you normally include a loop in your thread that checks the flag every second or so (depending on how precise you need the timing to be).
Also, the threading module is preferred over the lower lever thread module. The latter has been removed in python3.
This is not possible. The thread function has to finish. You can't join it from the outside.
Before you read on, know that I'm new to Python and very new to threading so forgive me if I misunderstand how threads work or make a rookie error :P
Short description of my goal:
The main thread (a) does some things (e.g. prints "begin!")
Main thread spawns a new thread (b) that first prints "Thread B
started" and then prints x+1 forever (1, 2, 3 ...)
Main thread prints "Woop!"
Then the end of the main thread is reached, it terminates itself and
then switches to thread b making b the main thread
Program is now running thread b as the main thread so is just
printing x+1 forever and a has been forgotten and is no longer
relevant
Ctrl+C will terminate thread b and effectively, the whole program
will be terminated because thread a doesn't exist anymore
Here's what I have so far (the basics):
import threading, time
def printCount():
print "Thread B started"
x = 0
while True:
time.sleep(1)
x = x + 1
print x
## User Code ##
print "begin!"
threadB = threading.Thread(target=printCount)
threadB.start()
print "woop!"
The requirements are:
I don't want to modify below the 'User Code' mark much at all. I
certainly don't want to wrap it in a class, a function or it's own
thread
Pressing Ctrl+C at any point should terminate the entire program
with no threads left running (Using something like: except
KeyboardInterrupt: os._exit(1)) inside User Code is fine
Thread a may continue to run instead of making thread b the main
thread, but in this case, I don't want the code to handle Ctrl+C
terminating the entire program inside the User Code section
This example is not my actual goal, just a simplified version of the problem I'm having. I'm trying to make an IRC framework where the user can import it and use the API very simply without messying their own code with threads and interrupts and the like. This is why it's important for the user code to be as clean as possible.
The framework would allow the user to create an IRC bot which runs forever, listening to commands whilst allowing the user to add their own commands. The Github link is here if you're interested (It's very WIP atm).
You cannot "switch" threads. So once you're done with your main thread, you have to wait for the other threads to terminate using the method join. But note this:
Since the join method is not interruptible with KeyboardInterrupt, you need to specify a timeout and loop over to detect user interrupts.
Since you can't force a thread to terminate, you have to implement a stop mecanism using threading.Event for instance
You also need to use threading.Lock to prevent concurrent access on shared resources, like sys.stdout (used when you print)
I gathered these aspects in a class called ThreadHandler, please have a look:
import threading, time
def printCount(lock, stop):
with lock:
print "Thread B started"
x = 0
while not stop.is_set():
time.sleep(1)
x = x + 1
with lock:
print x
class ThreadHandler():
STEP = 0.2
def __init__(self, target):
self.lock = threading.Lock()
self.stop = threading.Event()
args = (self.lock, self.stop)
self.thread = threading.Thread(target=target, args=args)
def start(self):
self.thread.start()
def join(self):
while self.thread.is_alive():
try:
self.thread.join(self.STEP)
except KeyboardInterrupt:
self.stop.set()
## User Code ##
print "begin!"
handler = ThreadHandler(target=printCount)
handler.start()
with handler.lock:
print "woop!"
handler.join()
Wrote a short note on another question yesterday having similar issues, this is a check you could implement in the subthread "b":
Instead of while 1: do the following:
def printCount():
main = None
for t in threading.enumerate():
if t.name == 'MainThread':
main = t
print "Thread B started"
x = 0
while main and main.isAlive():
time.sleep(1)
x = x + 1
print x
It would be a good idea to store main in the global scope for all threads to use isntead of having to look up the main thread each and every initation of the sub-thread.
But this would do the work in your example.
main will be the handle towards your main thread by iterating through all threads (.enumerate()) and then placing the thread called "MainThread" into main and then calling main.isAlive() to check if it's still running.
if main is None or False or if .isAlive() returns False it will indicate that the thread is either non-existant or dead, shutting down your subthread :)
You can't switch threads like that. It doesn't work like that.
However you could use signals with a global flag ALIVE:
import threading, time, signal
ALIVE = True
def handle_sigint(signum, frame):
global ALIVE
ALIVE = False
signal.signal(signal.SIGINT, handle_sigint)
def printCount():
print "Thread B started"
x = 0
while ALIVE: # <--- note the change
time.sleep(1)
x = x + 1
print x
## User Code ##
print "begin!"
threadB = threading.Thread(target=printCount)
threadB.start()
print "woop!"
signal.pause() # <--- wait for signals
Now it will gracefully quit after pressing CTRL+C.
I tried to look for an answer, but couldn't find anything relevant. Hence, the decision to ask.
I have a script A. At the beginning of script A, it calls script B (or a function, either works) in a separate thread.
A continues to do some task. I want to continue executing script A till script B doesn't finish.
How do I listen for the finishing of B while continuing with tasks of A?
For example,
Call Script B using subprocess, import file and run function (either way)
while(1):
count=count+1
if script B ended:
break
Can anyone illustrate how to check the "script B ended" part?
Here's a really simple way to do what you want:
import time
from threading import Thread
def stupid_work():
time.sleep(4)
if __name__ == '__main__':
t = Thread(target=stupid_work)
t.start()
while 1:
if not t.is_alive():
print 'thread is done'
break # or whatever
else:
print 'thread is working'
time.sleep(1)
The thread will die when it's done, so you just check intermittently to see if it's still around. You did not mention you want a return value. If you do, then you can pass the target function a queue, and replace if not t.is_alive() with if not q.empty(). Then do a q.get() to retrieve the return value when it's ready. And be sure to have the target put the return value in the queue, or you'll be waiting for quite a while.
If you're using the subprocess module you can do something like this.
from subprocess import Popen
proc = Popen(["sleep", "100"])
while True:
if proc.poll() is not None:
print("proc is done")
break
More on subprocess and poll here.