I'm facing a problem with Python and Threads: I have a daemon thread that continuously prints "TEST" in the console, every 5 seconds.
When the console is open, and I try to highlight a few lines of text, the thread stops and it doesn't continue until I press a key on the keyboard.
Here is my code:
import threading
import time
def thread_function():
t = threading.current_thread()
while getattr(t, 'do_run', True):
print('TEST')
time.sleep(5)
def main():
x = threading.Thread(target = thread_function)
x.daemon = True
x.start()
time.sleep(1000)
x.do_run = False
x.join()
if __name__ == '__main__':
main()
Which is the cause of this behavior?
Related
I am writing a program which constantly checks if certain IP adresses are connected to the network. If they are, nothing happens. If they are not connected for a certain time, an action is triggered.
My script works as intended as far as I can tell, however when I try to exit it using ctrl+c it simply doesnt stop.
I guess it has something to do with the threading that I am using, but I cant figure out what exactly it is.
This is my code so far:
import os
import time
from threading import Timer, Thread
import json
with open("ip_adresses.json", "r") as f:
ip_adresses_dict = json.load(f)
def timeout():
print("ACTION IS TRIGGERED")
# dummy Timer thread
print("dummy timer created")
t = Timer(999999999, timeout)
t.daemon = True
try:
while True:
ip_adress_reachable = []
for key, value in ip_adresses_dict.items():
if os.system(f"ping -c 1 -W 1 {value} > /dev/null") is 0: # this means its reachable
ip_adress_reachable.append(True)
else:
ip_adress_reachable.append(False)
print(ip_adress_reachable)
# if no ip adresses are reachable and no timer running, start a timer.
if any(ip_adress_reachable) == False and t.is_alive() == False:
print("starting a new thread")
t = Timer(15, timeout)
t.daemon = True
t.start()
# If in the meantime ip adress gets reachable cancel the timer.
elif any(ip_adress_reachable) == True and t.is_alive() == True:
# cancel the timer
print("timer was canceled")
t.cancel()
except KeyboardInterrupt:
print("quitting")
t.join(1)
I am kinda lost, because I though that deamon threads would stop after the main loop is done (i.e. after I press ctr+c)
If somebody could help me out, I would be very grateful.
After testing I found that all problem makes os.system() which catchs Ctrl+C to stop process running in os.system() - ping - and it doesn't send this information to Python.
If you run ping longer and you skip /dev/null
os.system(f"ping -c 5 -W 1 {value}")
then you will see that Ctrl+C stops ping
If I uses subprocess then I don't have this problem.
subprocess.call(f"ping -c 1 -W 1 {value} > /dev/null", shell=True)
Code which I used for test on Linux Mint 20 (based on Ubuntu 20.04)
#import os
import time
from threading import Timer, Thread
#import json
import subprocess
#with open("ip_adresses.json", "r") as f:
# ip_adresses_dict = json.load(f)
ip_adresses_dict = {
'x': '192.168.0.1',
'y': '192.168.0.2',
'z': '192.168.0.3',
}
def timeout():
print("ACTION IS TRIGGERED")
# dummy Timer thread
print("dummy timer created")
t = Timer(999999999, timeout)
t.daemon = True
try:
while True:
ip_adress_reachable = []
for key, value in ip_adresses_dict.items():
print('[DEBUG] start process')
#result = os.system(f"ping -c 1 -W 1 {value} > /dev/null")
#result = os.system(f"ping -c 5 -W 1 {value}")
result = subprocess.call(f"ping -c 1 -W 1 {value} > /dev/null", shell=True)
print('[DEBUG] end process')
ip_adress_reachable.append( result == 0 )
print(ip_adress_reachable)
# if no ip adresses are reachable and no timer running, start a timer.
if any(ip_adress_reachable) is False and t.is_alive() is False:
print("starting a new thread")
t = Timer(15, timeout)
t.daemon = True
t.start()
# If in the meantime ip adress gets reachable cancel the timer.
elif any(ip_adress_reachable) is True and t.is_alive() is True:
# cancel the timer
print("timer was canceled")
t.cancel()
except KeyboardInterrupt:
print("quitting")
if t.is_alive():
t.join(1)
Doc: Replacing os.system()
I have a script that runs but it has a tendency of hanging. I am trying to make another script to run it using threads, but the auto-restarting function does not seem to be working.
What I want this script to do is to restart the function every 900 seconds, or if it is possible, restart it whenever it hangs.
import time
import threading
import os
import functionname
def restart():
time.sleep(900)
os.execl('currentfilepath')
def res():
while True:
try:
# do your works
t = threading.Thread(target=restart, args=(), name='reset')
t.start()
functionname()
except:
print('error')
finally:
print('done')
if __name__ == '__main__':
res()
so I managed to find a way to solve this.
import multiprocessing
import time
t=600 # time to wait
def bar():
# do stuff
def barn():
for i in range(t*500): # runs for 500 times
# print ("Tick"+str(i)+'n') # just for tracking progress
time.sleep(1)
if i % t == 0:
print('restarting')
p = multiprocessing.Process(target=bar)
p.terminate
p = multiprocessing.Process(target=bar)
p.start()
if __name__ == '__main__':
p = multiprocessing.Process(target=bar)
p.start()
p1 = multiprocessing.Process(target=barn)
p1.start()
Probably not the most elegant but hey, it works.
Your answer works but it seems to be a one shot; on my system it stops running after 1 time. I changed the code to use a while loop instead; now it's working on my system:
def barn():
p = multiprocessing.Process(target=bar)
p.start()
i = 0
while(t > i):
print("running for " + str(i))
i += 1
time.sleep(1)
if i == t:
print('restarting')
p = multiprocessing.Process(target=bar)
p.terminate
p = multiprocessing.Process(target=bar)
p.start()
i = 0
Hey I am trying to have a loop be pausable from user input like having a input box in the terminal that if you type pause it will pause the loop and then if you type start it will start again.
while True:
#Do something
pause = input('Pause or play:')
if pause == 'Pause':
#Paused
Something like this but having the #Do something continually happening without waiting for the input to be sent.
Ok I get it now, here is a solution with Threads:
from threading import Thread
import time
paused = "play"
def loop():
global paused
while not (paused == "pause"):
print("do some")
time.sleep(3)
def interrupt():
global paused
paused = input('pause or play:')
if __name__ == "__main__":
thread2 = Thread(target = interrupt, args = [])
thread = Thread(target = loop, args = [])
thread.start()
thread2.start()
You can't directly, as input blocks everything until it returns.
The _thread module, though, can help you with that:
import _thread
def input_thread(checker):
while True:
text = input()
if text == 'Pause':
checker.append(True)
break
else:
print('Unknown input: "{}"'.format(text))
def do_stuff():
checker = []
_thread.start_new_thread(input_thread, (checker,))
counter = 0
while not checker:
counter += 1
return counter
print(do_stuff())
I have some background task that i want to start an be able to safely quit by user input.
To do that i have a thread in which a process pool with a continous task is started. There is a input lock to stop printing and to wait for user input and a event to stop the whole process.
What surprises me is that the processes seem to start and do their work if there is a time.sleep after the start of the thread with processpool (6th line in main).
import multiprocessing as mp
import time
import threading as tr
def init(e, l):
global stop_event
global input_lock
stop_event = e
input_lock = l
def stupid_task(n):
while not stop_event.is_set():
with input_lock:
print(n)
time.sleep(2)
def test_mng(n, event, lock):
with mp.Pool(n, initializer=init, initargs=(event, lock,)) as p:
print("before")
p.map(stupid_task, range(1, n + 1))
print("after")
p.close()
p.join()
def main():
i_lock = mp.Lock()
s_event = mp.Event()
thread = tr.Thread(target=test_mng, args=(3, s_event, i_lock))
init(s_event,i_lock)
thread.start()
time.sleep(1) # if this line is commented out only "before" is printed
while not stop_event.is_set():
input("")
with input_lock:
print("stopped")
eingabe = input("type q to quit")
if eingabe == "q":
stop_event.set()
if __name__ == "__main__":
main()
I ask myself what is stopping the process pool from doing it's work. Do i do something fundamentally wrong? The time.sleep seems a little bit hacky.
I my opinion, you are running your script from an IDE (like PyCharm), but not from the Console. Your IDE is catching the keyboard events.
You can simplify the processing:
The main process can wait for the user input,
The thread can do the "stupid task".
Here is a possible solution:
# coding: utf-8
import multiprocessing as mp
import threading as tr
import time
stop_event = None
def init(event):
global stop_event
stop_event = event
def stupid_task(n):
while not stop_event.is_set():
print(n)
time.sleep(2)
def test_mng(n, event):
with mp.Pool(n, initializer=init, initargs=(event,)) as p:
print("before")
p.map(stupid_task, range(1, n + 1))
print("after")
p.close()
p.join()
def main():
print("type 'q' <ENTER> to quit")
s_event = mp.Event()
init(s_event)
thread = tr.Thread(target=test_mng, args=(3, s_event,))
thread.start()
while not stop_event.is_set():
c = input("")
if c in "qQ":
stop_event.set()
if __name__ == "__main__":
main()
So I'm doing some testing with threads and I realised I could not stop and then start a thread. I could stop it, but starting it again was the issue.I want a script that adds 1 to a var when it is on then its stops when off by pressing shift to turn on and off.I have the detecting shift working (it is on another part of my code), but I just need to find out how to stop and start threadsHere is my test code:
from threading import Thread as th
import time as t
var = 0
def testDef():
global var
var += 1:
t.sleep(1)
test = th(target = testDef)
test.start()
while True:
menu = input("On, Off, Show Var")
if menu == "On":
test.start()
elif menu == "Off":
test._stop():
elif menu == "S":
print(var)
I know there are a few errors, but I mainly need the on and off threading to work.
Thanks, Jeff.
As far as I know, you can't actually stop and restart a thread as you can't use test.start() when the method has been terminated. However, you may be wondering to something similar by using threading.Condition to pause and later resume the execution.
You can read more about it in the documentation.
There is also an error in var += 1:, change it to var += 1
Here's a simple example on how to use threading.Event to enable two threads to communicate. This works by setting the internal flag of the Event to either True or False. While this internal flag is False you can ask thread a to wait (effectively block, which is not very efficient by the way). Then we use the two timers (b, c) to simulate a shift press every 5 seconds. In order to release a we set the event (internal flag = True). 5 seconds later, we clear the value of the internal flag and this will make thread a to block again.
import threading
def do(event):
flag = True
while flag:
if not event.isSet():
print "blocking"
event.wait()
else:
print "resuming"
def pressShift(event, enable):
print "Shift pressed"
if enable:
event.set()
else:
event.clear()
def main():
event = threading.Event()
a = threading.Thread(target=do, args=(event,))
b = threading.Timer(5, pressShift, args=(event, True)).start()
c = threading.Timer(10, pressShift, args=(event, False)).start()
a.start()
a.join()
if __name__ == "__main__":
main()
You cannot restart a thread that has already been started. What you can do, however, is to create another thread.
from threading import Thread as th
import time as t
var = 0
def testDef():
global var
var += 1
t.sleep(1)
test = th(target = testDef)
test.start()
while True:
menu = input("On, Off, Show Var")
if menu == "On":
test = th(target = testDef)
test.start()
elif menu == "Off":
test._stop()
elif menu == "S":
print(var)
Use an event object like this post, and check that event in your target functoin. Also, you need a new thread each time you re-start. The code shown below adds some debugging that should be useful. (Another approach is to build a custom stop function.)
import logging
import threading
import time as t
var = 0
logging.basicConfig(level=logging.DEBUG,
format='[%(levelname)s] (%(threadName)-10s) %(message)s',
)
def testDef(stop_event):
global var
print 'Thread Running', var
# inThread.stop()
while not stop_event.isSet():
var += 1
logging.debug('Var is %i' % var)
t.sleep(1)
# Use an event to track user input
testStopEvent = threading.Event()
testStopEvent.clear()
test = threading.Thread(name = 'test', target=testDef, args=((testStopEvent,)))
test.setDaemon(True)
while True:
menu = input("On = 1, Off = 2, Show Var = 3")
if menu == 1:
test.start()
elif menu == 2:
testStopEvent.set()
test.join() # Wait for the thread to finish
test = threading.Thread(target=testDef, args=((testStopEvent,))) # "re-start" thread
testStopEvent.clear() # Reset the stop event
elif menu == 3:
print(var)