I have a system utilization function, monitor(), that I want to run until the user stops it, by typing the number Zero, exit_collecting(). I don't want to abruptly end the program because that would negate the subsequent code.
I tried running the two functions using multithreading, exit_collecting() and monitor(), letting monitor() run until the user stops it by typing Zero, exit_collecting().
My code below threw a pile of tracebacks. I am a newbie at this, any ideas, any help would be great. Thank you. BTW I originally attempted using "try with an except for KeyboardInterrupt", but when using the IDLE (Spyder), the ctrl-c combo doesn't work (its assigned to "copy"), ctrl-c didn't work when I ran it from the console in Linux either.
def exit_collecting():
try:
val = int(input("Type 0 to exit data collection mode"))
if val == 0:
flag = 0
except:
print(val,"typo, enter 0 to exit data collection mode")
def monitor():
import time
import psutil
flag = 1
while flag > 0:
time.sleep(1)
print("cpu usuage:",psutil.cpu_percent())
from multiprocessing import Process
p1 = Process(target=exit_collecting)
p1.start()
p2 = Process(target=monitor)
p2.start()
p1.join()
p2.join()
Your version with multiprocessing is doomed to failure since each process has its own memory space and does not share the same variable flag
. It can be done with multiprocessing but you must use an implementation of flag
that uses shared memory.
A solution using threading is far simpler and your code should work if only you make one change. You neglected to declare flag
as global. This is required to ensure that functions exit_collecting
and monitor
are modifying the same variable. Without these declarations, each function is modifying a local flag
variablle:
def exit_collecting():
global flag
try:
val = int(input("Type 0 to exit data collection mode"))
if val == 0:
flag = 0
except:
print(val,"typo, enter 0 to exit data collection mode")
def monitor():
global flag
import time
import psutil
flag = 1
while flag > 0:
time.sleep(1)
print("cpu usuage:",psutil.cpu_percent())
from threading import Thread
p1 = Thread(target=exit_collecting)
p1.start()
p2 = Thread(target=monitor)
p2.start()
p1.join()
p2.join()
But perhaps the above code can be simplified by making the monitor
thread a daemon thread, that is a thread that it will automatically terminate when all non-daemon threads terminate (as currently written, it appears that function monitor
can be terminated at any point in processing). But in any case, the main thread can perform the function that exit_collecting
was performing. And there is no reason why you now can't use a keyboard interrupt (as long as you are waiting on an input
statement in the main thread):
def monitor():
import time
import psutil
while True:
time.sleep(1)
print("cpu usuage:",psutil.cpu_percent())
from threading import Thread
p = Thread(target=monitor)
p.daemon = True
p.start()
try:
input("Input enter to halt (or ctrl-C) ...")
except KeyboardInterrupt:
pass
"""
When the main thread finishes all non-daemon threads have completed
and therefore the monitor thread will terminate.
"""
Update: Allow monitor
thread to gracefully terminate and allow keyboard interrupt
I have simplified the logic a but just to use a simple global flag, terminate_flag
, initially False
, that is only read by the monitor
thread and therefore does not have to explicitly declare it as Global:
terminate_flag = False
def monitor():
import time
import psutil
while not terminate_flag:
time.sleep(1)
print("cpu usuage:", psutil.cpu_percent())
from threading import Thread
p = Thread(target=monitor)
p.start()
try:
input('Hit enter or ctrl-c to terminate ...')
except KeyboardInterrupt:
pass
terminate_flag = True # tell monitor it is time to terminate
p.join() # wait for monitor to gracefully terminate