How do I thread these functions? - python

I am trying to code an alarm in python that has 6 functions that need to multithread. 5 of these are alarms and one of them displays the time. The threads need to start and stop whenever the menu option is selected and when the alarm rings. The Display thread is the only thread that keeps going until the program stops. My current code for the alarm looks like this (I've removed a lot for the sake of clarity)
class TAlarm1 (threading.Thread):
def Alarm1():
while True:
#code which keeps running until the time is equal to the input given (expected to thread)
thread1 = threading.Thread(target=TAlarm1)
thread1.start()
def AlarmSelector():
print("Select an Alarm") #5 alarms will be added however each one accomplishes the same task. all of them need to run simultaneously
choice = int(input())
if choice == 1:
ala = TAlarm1()
ala.Alarm1()
if choice == 6:
DisplayTime() #goes back to displaying time
Whenever I run this code, the program displays no errors however it does not run the code in TAlarm1().
How can I solve this problem?

While your intent isn't clear to me. Here is how you can subclass Thread with its run method overridden and start it conditionally.
import threading
class TAlarm1 (threading.Thread):
def run(self):
n =4
while True:
#code which keeps running until the time is equal to the input given (expected to thread)
print(n,end=' | ')
n -= 1
if n < 0:
break
print()
t1 = TAlarm1()
if True:
t1.start()
A thread can only be started once so you have to make a new one every time you need it to run.
>>> t = TAlarm1()
>>> t.start()
4 | 3 | 2 | 1 | 0 |
>>> t.start()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python38\lib\threading.py", line 848, in start
raise RuntimeError("threads can only be started once")
RuntimeError: threads can only be started once
>>> t = TAlarm1()
>>> t.start()
4 | 3 | 2 | 1 | 0 |
>>>

The target parameter of Thread takes a callable. A class is a callable, but calling it just creates an instance of the class. Pass it a function instead:
import threading
def Alarm1():
print('Alarm1 called')
thread1 = threading.Thread(target=Alarm1)
thread1.start()

There are two basic ways of implementing threaded code in Python. You seem to have half of each.
The first implementation model is to put the logic to run in the thread into a function, then pass that function as the target argument when you create a threading.Thread instance:
import threading
import time
def worker(n):
for i in range(n):
print(i)
time.sleep(0.5)
my_thread = threading.Thread(target=worker, args=(10,))
my_thread.start()
# do other stuff in the main thread, if desired
my_thread.join()
The other implementation approach is to subclass threading.Thread and put the code to be run in the thread inside of the run method (or in other methods called from run). This is especially useful if your thread code has some complicated state and you want to be able to use additional methods to manipulate that state while the thread is running:
class MyThread(threading.Thread):
def __init__(self, n):
super().__init__()
self.n = n
self.unpaused = threading.Event()
self.unpaused.set() # we start unpaused
def run(self):
for i in range(self.n):
self.unpaused.wait() # block if we're paused
print(i)
time.sleep(0.5)
def pause(self):
self.unpaused.clear()
def unpause(self):
self.unpaused.set()
my_thread = MyThread(10)
my_thread.start()
# an example of inter-thread communication, we pause and unpause our thread using its methods
time.sleep(2)
my_thread.pause()
time.sleep(2)
my_thread.unpause()
my_thread.join()

Related

Run multiple python scripts in parallel from master script

I'd like to run multiple python scripts in parallel and start them from a master script. I did find solutions for this in previously asked questions, however, none of these worked if the scripts running in parallel contained loops.
Let's for example define two scripts.
Script 1:
array_1 = []
x = 0
while True:
array_1.append(x)
x = x + 1
Script 2:
array_2 = []
x = 0
while True:
array_2.append(x)
x = x + 1
Now I want to run both processes simultaneously. Previous solutions suggested the following code for a master script:
import script_1, script_2
exec(open(script_1))
exec(open(script_2))
While this is a solution for starting scripts from within another script, however, this will not run the two scripts in parallel.
What should such a master script actually look like ?
Thanks for your suggestions!
Edit
I tried the following threading approach:
def function_1():
print('function 1 started...')
while True:
print('1')
sleep(1)
def function_2():
print('function 2 started...')
while True:
print('2')
sleep(1)
thread_1 = Thread(target=function_1())
thread_2 = Thread(target=function_2())
thread_1.start()
thread_2.start()
thread_1.join()
thread_2.join()
print("thread finished")
It doesn't work, only the first function gets started so I get the following output:
function 1 started...
1
1
1
1
1
1
When you want to spawn a new thread, you need to pass the address of the function you want the thread to execute, and not to call it. What you are doing here is essentially spawning a new thread that immediately calls function_1() which of course runs forever.
Also, you won't be able to reach this line of code:
print("thread finished")
As the threads are executing a while loop - forever, so it is redundent..
from time import sleep
from threading import Thread
def function_1():
print('function 1 started...')
while True:
print('1')
sleep(1)
def function_2():
print('function 2 started...')
while True:
print('2')
sleep(1)
thread_1 = Thread(target=function_1)
thread_2 = Thread(target=function_2)
thread_1.start()
thread_2.start()
thread_1.join()
thread_2.join()
# print("thread finished") - redundant

How to kill a thread after N seconds? [duplicate]

This question already has answers here:
Is there any way to kill a Thread?
(31 answers)
Closed 2 years ago.
I want to create threads that will add something to an array, but, if they don't do that in less than 2 seconds, I want to terminate them.
This is a prof of concept, so the code is simple. Every second I want a thread to add that item in the list, so a thread runs after 0, 1, 2, 3 and 4 seconds. The idea is to not let the thread 3 and 4 run.
import threading, time
myList = []
def foo(value):
global myList
time.sleep(value)
print("Value: {}".format(value))
myList.append(value)
threads = []
for i in range(5):
th = threading.Thread(target=foo, args=(i,))
threads.append(th)
for th in threads:
th.start()
What do I do now? I tried using some other logic like using
th.join(timeout)
But that doesn't seem to work.
As I said in a comment you can't really "kill" a thread (externally). However they can "commit suicide" by returning or raising a exception.
Below is example of doing the latter when the thread's execution time has exceeded a given amount of time. Note that this is not the same as doing a join(timeout) call, which only blocks until the thread ends or the specified amount of time has elapsed. That's why the printing of value and its appending to the list happens regardless of whether the thread finishes before the call to join() times-out or not.
I got the basic idea of using sys.settrace() from the tutorial titled Different ways to kill a Thread — although my implementation is slightly different. Also note that this approach likely introduces a significant amount of overhead.
import sys
import threading
import time
class TimelimitedThread(threading.Thread):
def __init__(self, *args, time_limit, **kwargs):
self.time_limit = time_limit
self._run_backup = self.run # Save superclass run() method.
self.run = self._run # Change it to custom version.
super().__init__(*args, **kwargs)
def _run(self):
self.start_time = time.time()
sys.settrace(self.globaltrace)
self._run_backup() # Call superclass run().
self.run = self._run_backup # Restore original.
def globaltrace(self, frame, event, arg):
return self.localtrace if event == 'call' else None
def localtrace(self, frame, event, arg):
if(event == 'line' and
time.time()-self.start_time > self.time_limit): # Over time?
raise SystemExit() # Terminate thread.
return self.localtrace
THREAD_TIME_LIMIT = 2.1 # Secs
threads = []
my_list = []
def foo(value):
global my_list
time.sleep(value)
print("Value: {}".format(value))
my_list.append(value)
for i in range(5):
th = TimelimitedThread(target=foo, args=(i,), time_limit=THREAD_TIME_LIMIT)
threads.append(th)
for th in threads:
th.start()
for th in threads:
th.join()
print('\nResults:')
print('my_list:', my_list)
Output:
Value: 0
Value: 1
Value: 2
Results:
my_list: [0, 1, 2]
Join() is used to wait for the respective thread to finish. To terminate a thread, use stop().. You can try as follows:
time.sleep(N)
th.join()

Threads do not run (python3.6)

I found out that threading module in python 3.6 is not working properly.
problem is :
thread starts running before I call whatsoever_thread_name.start().
also, the code would not go to the next step from where I declare the first thread object in my code
Example :
import threading
def a():
while(1):
print(1)
def b():
while(1):
print(222)
t = threading.Thread(target = a())
v = threading.Thread(target = b())
result :
1
1
1
1
1
1
1
1
... infinitely
You need to assign the callback to target. Do not call the functions with ():
t = threading.Thread(target=a)
v = threading.Thread(target=b)
The threads will run these functions for you. The () means you are calling them yourself and attempting to assign the return value to target, but these functions don't return because they run forever.

How do I detect if a thread died, and then restart it?

I have an application that fires up a series of threads. Occassionally, one of these threads dies (usually due to a network problem). How can I properly detect a thread crash and restart just that thread? Here is example code:
import random
import threading
import time
class MyThread(threading.Thread):
def __init__(self, pass_value):
super(MyThread, self).__init__()
self.running = False
self.value = pass_value
def run(self):
self.running = True
while self.running:
time.sleep(0.25)
rand = random.randint(0,10)
print threading.current_thread().name, rand, self.value
if rand == 4:
raise ValueError('Returned 4!')
if __name__ == '__main__':
group1 = []
group2 = []
for g in range(4):
group1.append(MyThread(g))
group2.append(MyThread(g+20))
for m in group1:
m.start()
print "Now start second wave..."
for p in group2:
p.start()
In this example, I start 4 threads then I start 4 more threads. Each thread randomly generates an int between 0 and 10. If that int is 4, it raises an exception. Notice that I don't join the threads. I want both group1 and group2 list of threads to be running. I found that if I joined the threads it would wait until the thread terminated. My thread is supposed to be a daemon process, thus should rarely (if ever) hit the ValueError Exception this example code is showing and should be running constantly. By joining it, the next set of threads doesn't begin.
How can I detect that a specific thread died and restart just that one thread?
I have attempted the following loop right after my for p in group2 loop.
while True:
# Create a copy of our groups to iterate over,
# so that we can delete dead threads if needed
for m in group1[:]:
if not m.isAlive():
group1.remove(m)
group1.append(MyThread(1))
for m in group2[:]:
if not m.isAlive():
group2.remove(m)
group2.append(MyThread(500))
time.sleep(5.0)
I took this method from this question.
The problem with this, is that isAlive() seems to always return True, because the threads never restart.
Edit
Would it be more appropriate in this situation to use multiprocessing? I found this tutorial. Is it more appropriate to have separate processes if I am going to need to restart the process? It seems that restarting a thread is difficult.
It was mentioned in the comments that I should check is_active() against the thread. I don't see this mentioned in the documentation, but I do see the isAlive that I am currently using. As I mentioned above, though, this returns True, thus I'm never able to see that a thread as died.
I had a similar issue and stumbled across this question. I found that join takes a timeout argument, and that is_alive will return False once the thread is joined. So my audit for each thread is:
def check_thread_alive(thr):
thr.join(timeout=0.0)
return thr.is_alive()
This detects thread death for me.
You could potentially put in an a try except around where you expect it to crash (if it can be anywhere you can do it around the whole run function) and have an indicator variable which has its status.
So something like the following:
class MyThread(threading.Thread):
def __init__(self, pass_value):
super(MyThread, self).__init__()
self.running = False
self.value = pass_value
self.RUNNING = 0
self.FINISHED_OK = 1
self.STOPPED = 2
self.CRASHED = 3
self.status = self.STOPPED
def run(self):
self.running = True
self.status = self.RUNNING
while self.running:
time.sleep(0.25)
rand = random.randint(0,10)
print threading.current_thread().name, rand, self.value
try:
if rand == 4:
raise ValueError('Returned 4!')
except:
self.status = self.CRASHED
Then you can use your loop:
while True:
# Create a copy of our groups to iterate over,
# so that we can delete dead threads if needed
for m in group1[:]:
if m.status == m.CRASHED:
value = m.value
group1.remove(m)
group1.append(MyThread(value))
for m in group2[:]:
if m.status == m.CRASHED:
value = m.value
group2.remove(m)
group2.append(MyThread(value))
time.sleep(5.0)

Equivalent of setInterval in python

I have recently posted a question about how to postpone execution of a function in Python (kind of equivalent to Javascript setTimeout) and it turns out to be a simple task using threading.Timer (well, simple as long as the function does not share state with other code, but that would create problems in any event-driven environment).
Now I am trying to do better and emulate setInterval. For those who are not familiar with Javascript, setInterval allows to repeat a call to a function every x seconds, without blocking the execution of other code. I have created this example decorator:
import time, threading
def setInterval(interval, times = -1):
# This will be the actual decorator,
# with fixed interval and times parameter
def outer_wrap(function):
# This will be the function to be
# called
def wrap(*args, **kwargs):
# This is another function to be executed
# in a different thread to simulate setInterval
def inner_wrap():
i = 0
while i != times:
time.sleep(interval)
function(*args, **kwargs)
i += 1
threading.Timer(0, inner_wrap).start()
return wrap
return outer_wrap
to be used as follows
#setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
and it seems to me it is working fine. My problem is that
it seems overly complicated, and I fear I may have missed a simpler/better mechanism
the decorator can be called without the second parameter, in which case it will go on forever. When I say foreover, I mean forever - even calling sys.exit() from the main thread will not stop it, nor will hitting Ctrl+c. The only way to stop it is to kill python process from the outside. I would like to be able to send a signal from the main thread that would stop the callback. But I am a beginner with threads - how can I communicate between them?
EDIT In case anyone wonders, this is the final version of the decorator, thanks to the help of jd
import threading
def setInterval(interval, times = -1):
# This will be the actual decorator,
# with fixed interval and times parameter
def outer_wrap(function):
# This will be the function to be
# called
def wrap(*args, **kwargs):
stop = threading.Event()
# This is another function to be executed
# in a different thread to simulate setInterval
def inner_wrap():
i = 0
while i != times and not stop.isSet():
stop.wait(interval)
function(*args, **kwargs)
i += 1
t = threading.Timer(0, inner_wrap)
t.daemon = True
t.start()
return stop
return wrap
return outer_wrap
It can be used with a fixed amount of repetitions as above
#setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
or can be left to run until it receives a stop signal
import time
#setInterval(1)
def foo(a):
print(a)
stopper = foo('bar')
time.sleep(5)
stopper.set()
# It will stop here, after printing 'bar' 5 times.
Your solution looks fine to me.
There are several ways to communicate with threads. To order a thread to stop, you can use threading.Event(), which has a wait() method that you can use instead of time.sleep().
stop_event = threading.Event()
...
stop_event.wait(1.)
if stop_event.isSet():
return
...
For your thread to exit when the program is terminated, set its daemon attribute to True before calling start(). This applies to Timer() objects as well because they subclass threading.Thread. See http://docs.python.org/library/threading.html#threading.Thread.daemon
Maybe these are the easiest setInterval equivalent in python:
import threading
def set_interval(func, sec):
def func_wrapper():
set_interval(func, sec)
func()
t = threading.Timer(sec, func_wrapper)
t.start()
return t
Maybe a bit simpler is to use recursive calls to Timer:
from threading import Timer
import atexit
class Repeat(object):
count = 0
#staticmethod
def repeat(rep, delay, func):
"repeat func rep times with a delay given in seconds"
if Repeat.count < rep:
# call func, you might want to add args here
func()
Repeat.count += 1
# setup a timer which calls repeat recursively
# again, if you need args for func, you have to add them here
timer = Timer(delay, Repeat.repeat, (rep, delay, func))
# register timer.cancel to stop the timer when you exit the interpreter
atexit.register(timer.cancel)
timer.start()
def foo():
print "bar"
Repeat.repeat(3,2,foo)
atexit allows to signal stopping with CTRL-C.
this class Interval
class ali:
def __init__(self):
self.sure = True;
def aliv(self,func,san):
print "ali naber";
self.setInterVal(func, san);
def setInterVal(self,func, san):
# istenilen saniye veya dakika aralığında program calışır.
def func_Calistir():
func(func,san); #calışıcak fonksiyon.
self.t = threading.Timer(san, func_Calistir)
self.t.start()
return self.t
a = ali();
a.setInterVal(a.aliv,5);

Categories