Thanks to those who helped me figure out I needed to use threading to run a loop in a control script I have run, I now have an issue to try and control the thread - by starting or stopping it based on a function:
I want to start a process to get a motor to cycle through a movement based on a 'start' parameter sent to the controlling function, also I want to send a 'stop' parameter to stop the thread too - here's where I got to:
def looper():
while True:
print 'forward loop'
bck.ChangeDutyCycle(10)
fwd.ChangeDutyCycle(0)
time.sleep(5)
print 'backwards loop'
bck.ChangeDutyCycle(0)
fwd.ChangeDutyCycle(20)
time.sleep(5)
def looper_control(state):
t = threading.Thread(target=looper)
if state == 'start':
t.start()
elif state == 'stop':
t.join()
print 'looper stopped!!'
This starts the thread okay when I call looper_control('start') but throws an error when looper_control('stop'):
File "/usr/lib/python2.7/threading.py", line 657, in join
raise RuntimeError("cannot join thread before it is started")
RuntimeError: cannot join thread before it is started
EDIT: looper_control called from here
if "motor" in tmp:
if tmp[-1:] == '0':
#stop both pin
MotorControl('fwd',0,0)
print 'stop motors'
looper_control('stop')
elif tmp[-1:] == '2':
#loop the motor
print 'loop motors'
looper_control('start')
UPDATE: Ive not been able to stop the thread using the method suggested - I thought I had it!
here's where I am:
class sliderControl(threading.Thread):
def __init__(self,stop_event):
super(sliderControl,self).__init__()
self.stop_event = stop_event
def run(self):
while self.stop_event:
print 'forward loop'
bck.ChangeDutyCycle(10)
fwd.ChangeDutyCycle(0)
time.sleep(5)
print 'backwards loop'
bck.ChangeDutyCycle(0)
fwd.ChangeDutyCycle(20)
time.sleep(5)
def looper_control(state,stop_event):
if state == 'start':
t = sliderControl(stop_event=stop_event)
t.start()
elif state == 'stop':
#time.sleep(3)
stop_event.set()
#t.join()
print 'looper stopped!!'
called via:
if tmp[-1:] == '0':
#stop both pin
MotorControl('fwd',0,0)
print 'stop motors'
#stop_thread_event = threading.Event()
print 'stopping thread'
print stop_thread_event
looper_control('stop',stop_thread_event)
elif tmp[-1:] == '2':
#loop the motor
print 'loop motors'
global stop_thread_event
stop_thread_event = threading.Event()
print stop_thread_event
looper_control('start', stop_thread_event)
It looked like a separate thread event was being called by loop and stop, so I thought a global would sort it out but its just not playing ball. When I start the loop - it runs, but when I try to stop it, I get looper stopped!! , but the process just keeps running
Your top-level thread routine will need to become an event handler that listens to a Queue object (as in from Queue import Queue) for messages, then handles them based on state. One of those messages can be a shutdown command, in which case the worker thread function simply exits, allowing the main thread to join it.
Instead of time.sleep, use threading.Timer with the body of the timer sending a message into your event queue.
This is a substantial refactoring. But especially if you plan on adding more conditions, you'll need it. One alternative is to use a package that handles this kind of thing for you, maybe pykka.
To stop a python thread you can use threading.Event()
try this:
class YourClass(threading.Thread):
def __init__(self, stop_event):
super(YourClass, self).__init__()
self.stop_event = stop_event
def run(self):
while not self.stop_event.is_set():
# do what you need here (what you had in looper)
def looper_control(state, stop_event):
if state == 'start':
t = YourClass(stop_event=stop_event)
t.start()
elif state == 'stop':
stop_event.set()
and call to looper_control:
stop_thread_event = threading.Event()
looper_control(state, stop_thread_event)
you only can "start" once a thread
but you can lock and unlock the thread.
the best way to stop and start a thread is with mutex, Example:
#!/usr/bin/python
import threading
from time import sleep
mutex2 = threading.Lock()
#This thread add values to d[]
class Hilo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while True:
mutex2.acquire()
#Add values to d[]
d.append("hi from Peru")
mutex2.release()
sleep(1)
d=[];
hilos = [Hilo()]
#Stop Thread
#If you have more threads you need make a mutex for every thread
mutex2.acquire()
#Start treades, but the thread is lock
for h in hilos:
h.start()
#so you need do
#unlock THREAD<
mutex2.release()
#>START THREAD
#Sleep for 4 seconds
sleep(4)
#And print d[]
print d
print "------------------------------------------"
#WAIT 5 SECONDS AND STOP THE THREAD
sleep(5)
try:
mutex2.acquire()
except Exception, e:
mutex2.release()
mutex2.acquire()
#AND PRINT d[]
print d
#AND NOW YOUR TRHEAD IS STOP#
#When the thread is lock(stop), you only need call: mutex2.release() for unlock(start)
#When your thread is unlock(start) and you want lock(stop):
#try:
# mutex2.acquire()
#except Exception, e:
# mutex2.release()
# mutex2.acquire()
Related
For some reason, when the timeout is reached and the except is therefore executed, thread 2 is still "working", still expecting to get values from the user. Even though the closing_threads function is entered.
Why can't I terminate the thread? Why is it still waiting for keyboard entry?
If I add t2.join() then execution hangs indefinitely.
def main():
q2 = queue.Queue()
q1 = queue.Queue()
t1 = threading.Thread(target=nothing, name='t1', args=(q1,))
t2 = threading.Thread(target=get_interrupt_from_user, name='t2', args=(q2,))
t1.start()
t2.start()
try:
q2.get(timeout=4)
except:
...
closing_threads(t1, t2)
def closing_threads(t1, t2):
print('closing the threads')
t1.join()
t2.join()
print(t1.is_alive())
print(t2.is_alive())
def get_interrupt_from_user(q) -> None:
print('############ Thread 2 is starting! ############')
interrupt = False
while not interrupt:
print('use KeyboardInterrupt to stop the execution')
try:
input()
except KeyboardInterrupt:
print('KeyboardInterrupt exception took place')
else:
print('exit by KeyboardInterrupt!!!')
interrupt = True
print(f'interrupt took place = {interrupt}')
q.put(interrupt)
def nothing(q) -> None:
print('############ Thread 1 is starting! ############')
the second thread is technically not working, nor terminated, it is in a suspended state by the operating system, it will be terminated when it returns from this suspended state.
when you call input the operating system suspends the thread, and waits for input, then when input is available it wakes the thread and sends it the user input ... problem is that during that time it cannot handle interrupts ... because it is not executing code.
one way you can solve this is to declare the thread as daemon and not join it, so it will be killed when the other python threads die.
import queue
import threading
def main():
q2 = queue.Queue()
q1 = queue.Queue()
t1 = threading.Thread(target=nothing, name='t1', args=(q1,))
t2 = threading.Thread(target=get_interrupt_from_user, name='t2', args=(q2,),daemon=True)
t1.start()
t2.start()
try:
q2.get(timeout=4)
except:
...
closing_threads(t1, t2)
def closing_threads(t1, t2):
print('closing the threads')
t1.join()
print(t1.is_alive())
print(t2.is_alive())
def get_interrupt_from_user(q) -> None:
print('############ Thread 2 is starting! ############')
interrupt = False
while not interrupt:
print('use KeyboardInterrupt to stop the execution')
try:
input()
except KeyboardInterrupt:
print('KeyboardInterrupt exception took place')
else:
print('exit by KeyboardInterrupt!!!')
interrupt = True
print(f'interrupt took place = {interrupt}')
q.put(interrupt)
def nothing(q) -> None:
print('############ Thread 1 is starting! ############')
if __name__ == "__main__":
main()
other ways are sort of platform dependent and would involve summoning another processes that would signal the operating system to wake your thread up or terminate it and it gets messy really quick.
one last method is to use the select module on your stdin for this and create your own eventloop on the child thread, but this only works on linux.
new to python
new to twisted
My team wants me to make some existing code run in a seperate thread.
I've come up with a fictional example:
from twisted.internet import threads, reactor
from twisted.internet.defer import inlineCallbacks
from time import sleep
class SomeClass(object):
def __init__(self):
self.working = False
def set_working(self, is_working):
self.working = is_working
print 'Flag set to {}'.format(is_working)
#inlineCallbacks
def do_worker_thread(self):
# I want to make this call on the main thread
self.set_working(True)
# I want to do all this garbage on a separate thread and keep trucking on the main thread
# This mimics some calls in the real code. There is a call to deferToThread and a try
# except block there.
def thread_proc():
try:
for i in range(0, 100):
print 'Step %d starting'.format(i)
self.execute_step(i)
except Exception:
print 'An exception happened'
reactor.callInThread(thread_proc)
# When the worker thread is done, I want to call back 'on_thread_work_done'
def execute_step(self, num):
sleep(num)
print 'Worker thread: %d'.format(num)
def on_thread_work_done(self):
"""I want to be called back when the worker thread is done"""
self.set_working(False)
#inlineCallbacks
def do_main_thread(self):
for c in range(ord('a'), ord('z')+1):
sleep(c)
print 'Main thread: {}'.format(c)
if __name__ == "__main__":
someClass = SomeClass()
result = someClass.do_worker_thread()
result.addCallback(someClass.do_main_thread())
reactor.run()
The stuff on do_worker_thread currently runs on the main thread. I put a comment in there were I want it to run in a seperate thread. It is important that do_worker_thread returns immediately.
I expect the output to look something like:
Flag set to True
Step 0 starting
Main thread: a
Worker thread: 0
Worker thread: 1
Main thread: b
Worker thread: 2
Main thread: c
...
How can I alter what's in do_worker_thread, such that my set_working calls are on the main thread and it isn't set to False until the worker thread is done its work?
Try giving this a shot. It uses callFromThread() to schedule the work on the main thread.
from twisted.internet import threads, reactor
from twisted.internet.defer import inlineCallbacks, returnValue
from time import sleep
class SomeClass(object):
def __init__(self):
self.working = False
def set_working(self, is_working):
self.working = is_working
print 'Flag set to {}'.format(is_working)
#inlineCallbacks
def do_worker_thread(self):
# I want to make this call on the main thread
self.set_working(True)
# I want to do all this garbage on a separate thread and keep trucking on the main thread
# This mimics some calls in the real code. There is a call to deferToThread and a try
# except block there.
def thread_proc():
try:
for i in xrange(0, 10):
print 'Step {} starting'.format(i)
self.execute_step(i)
except Exception:
print 'An exception happened'
yield threads.deferToThread(thread_proc)
# When the worker thread is done, I want to call back 'on_thread_work_done'
self.on_thread_work_done()
returnValue(17)
def execute_step(self, num):
sleep(1)
print 'Worker thread: {}'.format(num)
def on_thread_work_done(self):
"""I want to be called back when the worker thread is done"""
self.set_working(False)
def do_main_thread(self):
for i in [chr(x) for x in range(ord('a'), ord('z')+1)]:
print 'Main thread: {}'.format(i)
sleep(1)
def thread_done(self, result):
print 'Thread done: {}'.format(result)
if __name__ == "__main__":
someClass = SomeClass()
# Schedule the threaded work
result = someClass.do_worker_thread().addCallback(someClass.thread_done)
# Schedule the main thread work
reactor.callFromThread(someClass.do_main_thread)
reactor.run()
You can use either callFromThread or blockingCallFromThread.
I'm writing a small concurrent program using Python 3.6. I have a question:
my program has a small Thread class (which simulates a thread);
this class has within it 3 methods that are executed as sub-threads:
class myThread(Thread):
def __init__(self, identifier):
super(myThread, self).__init__()
def fun1(self):
# broadcasts messages
def fun2(self):
# event that occurs when a message arrives
# do something
def fun3(self):
# event that occurs when a message arrives
# do something
def run(self):
t1 = Thread(target = self.fun1)
t2 = Thread(target = self.fun2)
t3 = Thread(target = self.fun3)
t1.start()
t2.start()
t3.start()
As you can see, fun1() sends broadcast messages (he sends objects) that the other 2 threads must receive. How can this thing be easily implemented in Python?
I have seen that the simplest way is to use Queue, but I have some doubts... where should I put this queue? How can a general method use the submitted object without emptying this queue (since the "broadcast" object must be used by the other methods)? How does a method perform its body every time a new object is added to the queue (as if it were an event)?
a good way to communicate between threads is using queue
it is better to use a designated queue for every thread
this is how you implement it in your code:
from queue import Queue
from threading import Thread
import time
# define some queues
fun2_q = Queue()
fun3_q = Queue()
class myThread(Thread):
def __init__(self, identifier):
super(myThread, self).__init__()
def fun1(self):
print('starting fun1')
# broadcasts messages
fun2_q.put('say something')
fun3_q.put('say something')
fun2_q.put('quit')
fun3_q.put('quit')
def fun2(self):
# event that occurs when a message arrives
# as a listener we should use infinite loop to monitor messages
# we will use non blocking way to read the queue using "if", also we can use fun2_q.get_nowait()
# instead of "if fun2_q.qsize() > 0:" statement
while True:
if fun2_q.qsize() > 0:
msg = fun2_q.get()
if msg == 'say something':
print('fun2 method saying hello')
elif msg == 'quit':
break # quit thread
# do other stuff below if no messages coming
time.sleep(0.1) # to stop while loop from abusing processor
print('fun2 terminating')
def fun3(self):
# event that occurs when a message arrives
# we will use a blocking way to read the queue
while True:
msg = fun3_q.get() # it will block here waiting for a message to come
if msg == 'say something':
print('fun3 method saying hello')
elif msg == 'quit':
break # quit thread
# can't do other stuff below if no messages coming, the loop will stuck waiting new message
# time.sleep(0.1) # no need for it since the loop will wait anyway
print('fun3 terminating')
def run(self):
t1 = Thread(target = self.fun1)
t2 = Thread(target = self.fun2)
t3 = Thread(target = self.fun3)
t1.start()
t2.start()
t3.start()
my_thread = myThread(1)
my_thread.run()
output:
starting fun1
fun2 method saying hello
fun3 method saying hello
fun3 terminating
fun2 terminating
I have 2 threads that are listening for data on 2 different UART lines that can come in any time. I also have a 3rd thread that is just a timer. In my main thread I would like to wait for any of these three threads to signal in order to trigger a parse data and update type function.
Is using 1 event with a separate flag that each thread would set before setting the event to indicate which one of them triggered the event an acceptable solution or is there a better way to do this that I'm missing?
Using python 2.7
For example:
'''
UART RX thread for GNSS
'''
def uart_rx_gnss( threadName, ser):
global event_flag
global rx_buffer
while(1):
line = ser.readline()
logger.debug(" GNSS >> " + str(line))
with t_lock:
rx_buffer = line
event_flag = EVENT_GNSS
t_event.set()
'''
UART RX thread for cc1350
'''
def uart_rx_cc1350( threadName, ser, t_lock, t_event):
global event_flag
global rx_buffer
while(1):
cc1350_buffer = ser.readline()
logger.debug(" CC1350 >> " + str(cc1350_buffer))
with t_lock:
rx_buffer = line
event_flag = EVENT_CC1350
t_event.set()
'''
Periodically update if no uart
'''
def periodic_update( threadName, t_lock, t_event ):
global event_flag
while(1):
time.sleep(3)
with t_lock:
event_flag = EVENT_TIMEOUT
t_event.set()
'''
Main
'''
def main(verbosity="info", mode="normal"):
# SIGING Handler
signal.signal(signal.SIGINT, signal_handler)
######### GLOBAL VARIABLES #########
global event_flag
ser = ic.initialize_uart('/dev/ttymxc6', 9600)
thread.start_new_thread( uart_rx_gnss, ("Thread-GNSS-RX", ser ) )
ser = ic.initialize_uart('/dev/ttymxc4')
thread.start_new_thread( uart_rx_cc1350, ("Thread-cc1350-RX", ser, lock, event ) )
thread.start_new_thread( periodic_update, ("Updater", lock, event ) )
# Main Loop
while (running == True):
event.wait()
if (event_flag == EVENT_TIMEOUT):
logger.info("EVENT: TIMEOUT")
# UPDATE
elif (event_flag == EVENT_GNSS):
logger.info("EVENT: GNSS")
# Parse rx_buffer
elif (event_flag == EVENT_CC1350):
logger.info("EVENT: CC1350")
# Parse rx_buffer
else:
logger.info("EVENT UNKNOWN")
event_flag = 0
event.clear()
This will explode.
All you need are two close events, and your global evetn_flag will be overwritten in a race-condition.
You should be using queues for that.
https://docs.python.org/3/library/queue.html
Queues will preserve the order, and warrant your main thread will process all events that arrived.
You can post an arbitrary data structure to the Queue - so, since yu alredy have an event-type "quasi-enumeration", you can post a tuple with this event_type as first element, and whatever data you have to comunicate across threads as second element. Just create a queue.Queue object before spawning your threads, you can even set it as a global variable, and use the queue's get method instead of event.wait().
I need a sleep() method which can be aborted (as described here or here).
My approach is to let a threading.Event.wait() timeout at the specified duration:
def abortable_sleep(secs, abort_event):
abort_event.wait(timeout=secs)
abort_event.clear()
After calling abortable_sleep(10, _abort) I can now (from another thread) call _event.set(_abort) to let abortable_sleep() terminate before the 10 seconds.
Example:
def sleeping_thread():
_start = time.perf_counter()
print("%f thread started" % (time.perf_counter() - _start))
abortable_sleep(5, _abort)
print("%f thread stopped" % (time.perf_counter() - _start))
if __name__ == '__main__':
_abort = threading.Event()
while True:
threading.Thread(target=sleeping_thread).start()
time.sleep(3)
_abort.set()
time.sleep(1)
Output:
0.000001 thread started
3.002668 thread stopped
0.000002 thread started
3.003014 thread stopped
0.000001 thread started
3.002928 thread stopped
0.000001 thread started
This code is working as expected but I still have some questions:
isn't there an easier way to have s.th. likea sleep() which can be aborted?
can this be done more elegant? E.g. this way I have to be careful with the Event instance which is not bound to an instance of abortable_sleep()
do I have to expect performance issues with high frequency loops like while True: abortable_sleep(0.0001)? How is the wait()-timeout implemented?
I have a wrapper class which basically slaps some sleep semantics on top of an Event. The nice thing is that you only have to pass around a Sleep object, which you can call sleep() on several times if you like (sleep() is not thread safe though) and that you can wake() from another thread.
from threading import Event
class Sleep(object):
def __init__(self, seconds, immediate=True):
self.seconds = seconds
self.event = Event()
if immediate:
self.sleep()
def sleep(self, seconds=None):
if seconds is None:
seconds = self.seconds
self.event.clear()
self.event.wait(timeout=seconds)
def wake(self):
self.event.set()
Usage example:
if __name__ == '__main__':
from threading import Thread
import time
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(created)d - %(message)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.info("sleep")
s = Sleep(3)
logger.info("awake")
def wake_it(sleeper):
time.sleep(1)
logger.info("wakeup!")
sleeper.wake()
logger.info("sleeping again")
s = Sleep(60, immediate=False)
Thread(target=wake_it, args=[s]).start()
s.sleep()
logger.info("awake again")
The above might output something like this:
1423750549 - sleep
1423750552 - awake
1423750552 - sleeping again
1423750553 - wakeup!
1423750553 - awake again
Exactly what you did, but encapsulated in a class.
Due to race conditions, your solution is not always perfectly correct. You should use a threading.BoundedSemaphore() instead. Call aquire() immediately after creating it. When you want to sleep, call acquire() with a timeout, then call release() if the acquire() returned true. To abort the sleep early, call release() from a different thread; this will raise ValueError if there is no sleep in progress.
Using an event instead is problematic if the other thread calls set() at the wrong time (i.e. at any time other than when you are actually waiting on the event).
I'd wrap the sleep/abort function up in a new class:
class AbortableSleep():
def __init__(self):
self._condition = threading.Condition()
def __call__(self, secs):
with self._condition:
self._aborted = False
self._condition.wait(timeout=secs)
return not self._aborted
def abort(self):
with self._condition:
self._condition.notify()
self._aborted = True
I'd then also supply a Thread subclass to manage the sharing of the wakeup routine on a per-thread basis:
class ThreadWithWakeup(threading.Thread):
def __init__(self, *args, **kwargs):
self.abortable_sleep = AbortableSleep()
super(ThreadWithWakeup, self).__init__(*args, **kwargs)
def wakeup(self):
self.abortable_sleep.abort()
Any other thread with access to this thread can call wakeup() to abort the current abortable_sleep() (if one is in progress).
Using ThreadWithWakeup
You can create threads using the ThreadWithWakeup class, and use it like this:
class MyThread(ThreadWithWakeup):
def run(self):
print "Sleeper: sleeping for 10"
if self.abortable_sleep(10):
print "Sleeper: awoke naturally"
else:
print "Sleeper: rudely awoken"
t = MyThread()
t.start()
print "Main: sleeping for 5"
for i in range(5):
time.sleep(1)
print i + 1
print "Main: waking thread"
t.wakeup()
The output of which looks like:
Sleeper: sleeping for 10
Main: sleeping for 5
1
2
3
4
5
Main: waking thread
Sleeper: rudely awoken
Using AbortableSleep on its own
You can also use the AbortableSleep class on its own, which is handy if you can't use the ThreadWithWakeup class for some reason (maybe you're in the main thread, maybe something else creates the threads for you, etc.):
abortable_sleep = AbortableSleep()
def run():
print "Sleeper: sleeping for 10"
if abortable_sleep(10):
print "Sleeper: awoke naturally"
else:
print "Sleeper: rudely awoken"
threading.Thread(target=run).start()
print "Main: sleeping for 5"
for i in range(5):
time.sleep(1)
print i + 1
print "Main: aborting"
abortable_sleep.abort()