I am getting headache, trying to figure out how to deal with 2 threads in Python.
My Idea was to create one thread for blinking LEDs, that have infinite while loop, and when global variable changes to True,it starts to blink etc, but it is always in infinite loop.
other main thread, will be waiting for signal to blink, but also if the signal is while blinking, it will reset global blinking timer, so it has to be in separate thread.
Problem I am having, when I start LEDs thread from main thread, because LED thread has infinite loop, it stops main thread from running any further than flashThread.start()
if __name__ == "__main__":
print('starting main...')
flashThread = threading.Thread(name='SFlashing', daemon = True, target=Flash)
flashThread.start()
while(True):
print('running main...')
time.sleep(2)
it never gets to running main...
Flash() is just infinite while loop and depending on global variables it does stuff...
Here is an example of a main thread printing running main... + a parallel thread incrementing a variable count, based on your explanations. Your code should work, maybe could you give us more information about the Flash loop so we can help you ?
import threading
import time
def Flash():
count = 0
while True:
print("count", count)
count += 1
time.sleep(1)
print('starting main...')
flashThread = threading.Thread(name='SFlashing', daemon = True, target=Flash)
flashThread.start()
while(True):
print('running main...')
time.sleep(2)
Output:
starting main...
count 0
running main...
count 1
running main...
count 2
count 3
running main...
** EDIT **
Here there is no more time.sleep()in Flash, until the global variable totois changed in the main loop.
import threading
import time
global toto
toto = 0
def Flash():
global toto
count = 0
while True:
print("count", count)
count += 1
if toto == 2:
print("YEEHA")
time.sleep(2)
print('starting main...')
flashThread = threading.Thread(name='SFlashing', daemon = True, target=Flash)
flashThread.start()
while(True):
print('running main...')
time.sleep(1)
toto = 2
Related
i'm currently trying to unterstand threading in python and i wrote a program that ideally would have 2 threads alternating between incrementing and decrementing a global variable but no matter how i spread out the lock it inevitably becomes out of sync.
number = 0
lock = threading.Lock()
def func1():
global number
global lock
while True:
try:
lock.acquire()
number += 1
finally:
lock.release()
print(f"number 1 is: {number}")
time.sleep(0.1)
def func2():
global number
global lock
while True:
try:
lock.acquire()
number -= 1
finally:
lock.release()
print(f"number 2 is: {number}")
time.sleep(0.1)
t1 = threading.Thread(target=func1)
t1.start()
t2 = threading.Thread(target=func2)
t2.start()
t1.join()
t2.join()
the output should look something like this:
number 1 is: 1
number 2 is: 0
number 1 is: 1
number 2 is: 0
number 1 is: 1
number 2 is: 0
number 1 is: 1
number 2 is: 0
but right now it looks like this:
number 1 is: 1
number 2 is: 0
number 1 is: 1
number 2 is: 0
number 2 is: -1number 1 is: 0
number 2 is: -1number 1 is: 0
number 1 is: 1number 2 is: 0
any idea how to do this without falling out of sync?
First, avoid using global variables with threads in python. Use a queue to share the variables instead.
Second, the lock acquisition in non-deterministic. At the moment a lock is released, you have no guarantee that the other thread will grab it. There is always a certain probability that the thread that just released the lock can grab it again before the other thread.
But in your case, you can avoid problems because you know the state that the variable needs to be to accept modifications by one thread or the other. So, you can enforce the protection for modification by verifying if the variable is in the right state to accept a modification.
Something like:
from threading import Thread
import time
from queue import Queue
def func1(threadname, q):
while True:
number = q.get()
if number == 0:
number += 1
print(f"number 1 is: {number}")
q.put(number)
time.sleep(0.1)
def func2(threadname, q):
while True:
number = q.get()
if number == 1:
number -= 1
print(f"number 2 is: {number}")
q.put(number)
time.sleep(0.1)
queue = Queue()
queue.put(0)
t1 = Thread(target=func1, args=("Thread-1", queue))
t2 = Thread(target=func2, args=("Thread-2", queue))
t1.start()
t2.start()
t1.join()
t2.join()
thanks for all your answers, i remember seing someone in the comments mentioned using events or something like that and that solved the issue. here's the code:
number = 0
event_number = threading.Event()
event_number.clear()
def func1():
global number
global event_number
while True:
if not event_number.is_set():
number += 1
print(f"func 1 is {number}")
event_number.set()
else:
pass
time.sleep(2)
def func2():
global number
global event_number
while True:
if event_number.is_set():
number -= 1
print(f"func 2 is {number}")
event_number.clear()
else:
pass
time.sleep(2)
t1 = threading.Thread(target=func1)
t2 = threading.Thread(target=func2)
t1.start()
t2.start()
t1.join()
t2.join()
now i notice that sometimes one of the loops will either not wait it's alloted time and print right away or wait double the time but at least the number only stays within those 2 values.
For starters, time.sleep is not exactly accurate. And depending on the python-implementation you're using (most likely cpython) multithreading might not quite work the way you're expecting it to. These two factors allow the initially correct timing of your threads to get out of sync within fairly short time.
There solution for this problem is to enforce alternate operation on the variable by the two threads via two locks:
import time
import threading
var = 0
def runner(op, waitfor, release):
global var
while True:
try:
# wait for resource to free up
waitfor.acquire()
# operation
var = op(var)
print(f"var={var}")
finally:
# notify other thread
release.release()
time.sleep(0.1)
# init locks for thread-synchronization
lock_a = threading.Lock()
lock_b = threading.Lock()
lock_a.acquire()
lock_b.acquire()
# create and start threads (they'll wait for their lock to be freed)
thread_a = threading.Thread(target=runner, args=(lambda v: v - 1, lock_a, lock_b))
thread_b = threading.Thread(target=runner, args=(lambda v: v + 1, lock_b, lock_a))
thread_a.start()
thread_b.start()
# let thread_b start the first operation by releasing the lock
lock_b.release()
In the above code, each thread has a lock that can be used to notify it, that the resource may be used by it. Thus threads can hand control over the global variable to each other.
I am trying to create a multithreading program that will run one thread for three seconds, then 'pause' the thread using event objects, wait for a few seconds, then repeat the process over again. here is my code:
import threading
import time
counter = 1
def control():
global counter
test_event.wait()
while(test_event.is_set()):
print 'waiting 3 seconds'
time.sleep(3)
event.set()
time.sleep(3)
event.clear()
if(counter == 1):
counter = counter - 1
def function():
global counter
event.wait()
while (event.is_set()):
test_event.clear()
print 'event is set to high'
time.sleep(1)
print 'event is set to low'
test_event.set()
event = threading.Event()
test_event = threading.Event()
t1 = threading.Thread(target = control)
t2 = threading.Thread(target = function)
t1.start()
t2.start()
while(counter == 1):
test_event.set()
the output I am desiring should look like this:
waiting 3 seconds
event is set to high
event is set to high
event is set to high
event is set to low
waiting 3 seconds
event is set to high
....
....
and that keeps repeating.
the output I am currently receiving however is this:
waiting three seconds
event is set to high
event is set to high
event is set to high
waiting 3 seconds
event is set to low
waiting 3 seconds
waiting 3 seconds
waiting 3 seconds
...
...
and that keeps repeating.
Can anybody detect where I am messing up, and possibly offer any advice for me to fix? I cannot seem to figure out what I am doing wrong.
P.S. I am aware that this code probably is constructed very poorly, but I am completely new to multithreading...sorry in advance!
I've already referred to this thread, but it seems to be outdated
and there doesn't seem to be a clean explanation
Python daemon thread does not exit when parent thread exits
I'm running python 3.6 and trying to run the script from either IDLE or Spyder IDE.
Here is my code:
import threading
import time
total = 4
def creates_items():
global total
for i in range(10):
time.sleep(2)
print('added item')
total += 1
print('creation is done')
def creates_items_2():
global total
for i in range(7):
time.sleep(1)
print('added item')
total += 1
print('creation is done')
def limits_items():
#print('finished sleeping')
global total
while True:
if total > 5:
print ('overload')
total -= 3
print('subtracted 3')
else:
time.sleep(1)
print('waiting')
limitor = threading.Thread(target = limits_items, daemon = True)
creator1 = threading.Thread(target = creates_items)
creator2 = threading.Thread(target = creates_items_2)
print(limitor.isDaemon())
creator1.start()
creator2.start()
limitor.start()
creator1.join()
creator2.join()
print('our ending value of total is' , total)
limitor thread doesn't seem to be ending despite being a daemon thread.
Is this a way to get this working from IDLE or Spyder?
Thanks.
I had the same Problem and solved it by using multiprocessing instead of threading:
from multiprocessing import Process
import multiprocessing
from time import sleep
def daemon_thread():
for _ in range(10):
sleep(1)
print("Daemon")
if __name__ == '__main__':
multiprocessing.freeze_support()
sub_process = Process(target = daemon_thread, daemon = True)
sub_process.start()
print("Exiting Main")
I haven't yet really understood why I need the call to freeze_support() but it makes the code work.
Is is possible to stop a thread prematurely when it is stuck inside a while loop? Below is my sample code, which runs correctly, since each time it calls loop_thread it will check to see if the threading.Event() flag is set. When attempting to run the code for a file that processes information much longer than each second, there is no way to stop the entire function from continuing its execution until the next iteration. For example, if I run dld_img_thread, it takes about 5 minutes to complete its execution and recheck the while loop to see if should proceed. What I want to have happen is kill the dld_img_thread at a time shorter than 5 minutes (e.g. 1 minute). I don't care if the data is lost, just that the thread stops before the function finishes execution. Thank you
import threading, time, pythoncom, read_mt0
import powerfail_debugport_reader as pf_dbg_rdr
import powerfail_firmware_downloader as pf_fwdld
def loop_thread(thread_name, thread_event):
loopCnt = 0
print "\nstarting {}".format(thread_name)
print "is {0} alive? {1}\n".format(thread_name, L00P_thread.is_alive())
while not thread_event.is_set():
print("value of loopCnt = {}".format(loopCnt))
loopCnt += 1
time.sleep(1)
print('stopping {}\n'.format(thread_name))
def image_dld(thread_name, thread_event):
pythoncom.CoInitializeEx(pythoncom.COINIT_MULTITHREADED)
print "\nstarting {}".format(thread_name)
print "is {0} alive? {1}\n".format(thread_name, dld_img_thread.is_alive())
while not thread_event.is_set():
pf_fwdld.power_fail_test()
print('stopping {}'.format(thread_name))
def debug_port_thread(thread_name, thread_event):
pythoncom.CoInitializeEx(pythoncom.COINIT_MULTITHREADED)
print "\nstarting {}".format(thread_name)
print "is {0} alive? {1}\n".format(thread_name, debug_thread.is_alive())
pf_dbg_rdr.debug_port_reader()
print('\nstopping {}'.format(thread_name))
def main():
global L00P_thread, debug_thread
pf_dbg_rdr.samurai_event = threading.Event()
L00P_thread = threading.Thread(target=loop_thread, \
args=('L00P_thread', pf_dbg_rdr.samurai_event))
dld_img_thread = threading.Thread(target=image_dld, \
args=('image_download', pf_dbg_rdr.samurai_event))
debug_thread = threading.Thread(target=debug_port_thread, \
args=('debug_port_reader', pf_dbg_rdr.samurai_event))
L00P_thread.start()
dld_img_thread.start()
debug_thread.start()
debug_thread.join()
if __name__ == '__main__':
main()
print('processes stopped')
print "Exiting Main Thread"
Use a second variable in your while condition that you can change once your timeout is reached.
For example:
shouldRun = True
while not thread_event.is_set() and shouldRun:
print("value of loopCnt = {}".format(loopCnt))
loopCnt += 1
time.sleep(1)
if loopCnt > 60: shouldRun = False
would stop after 60 iterations (about 60 seconds given you sleep for 1 second on each iteration).
Can anyone please give me a small and simple example on how to use threading with pyserial communication.
I am googling for over three days and I am still illeterate and I dont even have a working piece of code which integrate both of them
Basically I am aiming to use threading in this scenario:
Have a serial communication continuously go on in the back ground to attain certain value (say A) from an MCU.
Stop attaining value A - then attain value B...and start continuously attaining value A again.
You can find some basic code here.
import threading
import time
import sys
import serial
import os
import time
def Task1(ser):
while 1:
print "Inside Thread 1"
ser.write('\x5A\x03\x02\x02\x02\x09') # Byte ArrayTo Control a MicroProcessing Unit
b = ser.read(7)
print b.encode('hex')
print "Thread 1 still going on"
time.sleep(1)
def Task2(ser):
print "Inside Thread 2"
print "I stopped Task 1 to start and execute Thread 2"
ser.write('x5A\x03\x02\x08\x02\x0F')
c = ser.read(7)
print c.encode('hex')
print "Thread 2 complete"
def Main():
ser = serial.Serial(3, 11520)
t1 = threading.Thread(target = Task1, args=[ser])
t2 = threading.Thread(target = Task2, args=[ser])
print "Starting Thread 1"
t1.start()
print "Starting Thread 2"
t2.start()
print "=== exiting ==="
ser.close()
if __name__ == '__main__':
Main()
There's no factual basis for the claim by Task2:
print "I stopped Task 1 to start and execute Thread 2"
Your implementation starts one thread then immediately starts the other without stopping the first. This means that the ser.read and ser.write commands could interfere with each other.
The simplest thing you could do to address this is to introduce variables that allow communication:
import sys
import os
import time
import threading
thread_flag = None
def Report(s):
print s
sys.stdout.flush() # helps to ensure messages from different threads appear in the right order
def Stop():
global thread_flag
thread_flag = 'stop'
def Task1(ser):
Report("Inside Thread 1")
global thread_flag
thread_flag = 'go'
while True:
Report("Thread 1 waiting for permission to read")
while thread_flag != 'go': time.sleep( 0.001 )
while thread_flag == 'go':
Report("Thread 1 is reading")
#ser.write('\x5A\x03\x02\x02\x02\x09') # Byte ArrayTo Control a MicroProcessing Unit
#b = ser.read(7)
#Report(b.encode('hex'))
time.sleep(1)
if thread_flag == 'stop': break
else: thread_flag = 'paused' # signals that the inner loop is done
Report("Thread 1 complete")
def Task2(ser):
Report("Inside Thread 2")
global thread_flag
thread_flag = 'pause' # signals Task1 to pause
while thread_flag != 'paused': time.sleep(0.001) # waits for Task1 inner loop to exit
Report("I stopped Task 1 to start and execute Thread 2")
#ser.write('x5A\x03\x02\x08\x02\x0F')
#c = ser.read(7)
#Report(c.encode('hex'))
thread_flag = 'go' # signals Thread 1 to resume
Report("Thread 2 complete")
def Main():
ser = None # serial.Serial(3, 11520)
t1 = threading.Thread(target = Task1, args=[ser])
t2 = threading.Thread(target = Task2, args=[ser])
Report("Starting Thread 1")
t1.start()
time.sleep(3)
Report("Starting Thread 2")
t2.start()
if __name__ == '__main__':
Main()
That approach uses a global variable, which is often frowned upon. You could instead make Task1 and Task2 methods of an object self that carries both self.ser and self.thread_flag as attributes.
For any inter-thread communication more complex than this, you need to investigate locks, mutexes and semaphores (e.g. threading.Lock)