i've a working function which stops when the user writes exit, but i also have another function which doesn't stop so cmd just keeps staying open and won't close like it should as the other function keeps changing the cmd text color
import os,webbrowser,time,random,sys
from threading import Thread
def fun1():
Q=1
while Q==1:
print ('would you like to:')
print('1.launch an applcation')
print('2.browse the internet')
print('========================================')
bruv=input('your answer: ')
if bruv in ('1','launch','launch app','launch an application'):
print('========================================')
print('what app would you like to open?')
print('========================================')
x=input('your answer: ')
if x not in ('word'):
y=x+'.exe'
os.startfile(y)
else:
z='win'+x
os.startfile(z)
if bruv in ('2','browse the internet','browse','browse internet'):
print('========================================')
print ('where would you like to go?')
print('========================================')
p=input('your answer: ')
p='www.'+p+'.com'
webbrowser.open(p)
print('========================================')
print ('ok')
print('========================================')
print ('wanna continue?')
if input() in ('exit','no','quit','nope','close'):
print('========================================')
print ('ok! thanks for using my bot!')
print('========================================')
time.sleep(1)
Q+=1
countdown=3
while countdown>=0:
if countdown!=0:
print (countdown)
time.sleep(1)
countdown-=1
else:
sys.exit()
def fun2():
what=1
while what==1:
os.system('color E')
time.sleep(0.2)
os.system('color A')
time.sleep(0.2)
os.system('color C')
time.sleep(0.2)
os.system('color B')
time.sleep(0.2)
os.system('color D')
time.sleep(0.2)
else:
sys.exit()
t1=Thread(target=fun1)
t2=Thread(target=fun2)
t1.start()
t2.start()
In this code fun2 keeps rolling changing the color and wont close CMD
also i know this code is pretty bad i'm just starting python.
So the problem here is that your whole script (which starts both of your functions/threads) will on default only end when all the threads it started have stopped. So all your functions need to return at some point, but your fun2() will never finish as the endless loop while what==1 will always run as what is always equal to 1. (As a side note, the convention for endless loops in Python is to use while True: ...).
To tell a Thread that it should finish when all other threads have, you have to make it a Daemon. You might want to look here, where the documentation says:
A thread can be flagged as a “daemon thread”. The significance of this
flag is that the entire Python program exits when only daemon threads
are left. The initial value is inherited from the creating thread. The
flag can be set through the daemon property or the daemon constructor
argument.
So in your example above, making t2 a deamon should work.
...
t1 = Thread(target=fun1)
t2 = Thread(target=fun2)
t2.deamon = True
t1.start()
t2.start()
P.S.: Also be aware that color does not work in all terminals and operating systems (e.g. MacOS)
Related
I have some program logic that works as follows:
for i in range(10**6):
foo(i)
print("foo executed with parameter", i)
bar(i)
print("bar executed with parameter", i)
The problem arises when I want to interrupt the loop with Ctrl+C to raise a KeyboardInterrupt.
I make sure that the function bar(i) always runs after the function foo(i); i.e. the loop cannot be interrupted between the two function calls (or, if it is, I want to complete the loop before exiting). If the interrupt is received while one of the functions is being executed, I want both to finish before exiting.
How is this achievable (with a try...except statement or otherwise) in Python 3?
Thank you to Omer Ben Haim for providing an answer in the comments.
Indeed, the SIGINT signal can be captured using the signal module. Here is some proof-of-concept code that demonstrates this:
import signal
import time
stop = False
def handler(sig, frame):
global stop
stop = True
signal.signal(signal.SIGINT, handler)
############
i = 0
while i<10**6 and not stop:
print("Part 1:", i)
time.sleep(0.5)
print("Part 2:", i)
time.sleep(0.5)
i += 1
This could be done rather easily using a flag.
When a KeyboardInterrupt is raised(E.g. Ctrl+c is pressed), you capture it and set the quit_loop flag to True.
When we finish what we need to do, we check if we need to quit the loop and if we do then we break.
If you want to fully exit the program you can replace break with exit().
quit_loop = False
for i in range(10):
try:
foo()
except KeyboardInterrupt:
quit_loop = True
bar()
if quit_loop:
break
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.
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?
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.