Communicate data between threads in python - python

I am new to python I have very little knowledge about threads in python. Here is my sample code.
import threading
from threading import Thread
import time
check = False
def func1():
print ("funn1 started")
while check:
print ("got permission")
def func2():
global check
print ("func2 started")
time.sleep(2)
check = True
time.sleep(2)
check = False
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
What I want is to see see "got permission" as the output. But with my current code it is not happening. I assume that the func1 thread is closed before func2 changes the check value to True.
How can I keep func1 alive?
I have researched on the internet but I could not found a solution.
Any help would be appreciated.
Thank you in advance!

The problem here is that func1 performs the check in the while loop, finds it is false, and terminates. So the first thread finishes without printing "got permission".
I don't think this mechanism is quite what you are looking for. I would opt to use a Condition like this,
import threading
from threading import Thread
import time
check = threading.Condition()
def func1():
print ("funn1 started")
check.acquire()
check.wait()
print ("got permission")
print ("funn1 finished")
def func2():
print ("func2 started")
check.acquire()
time.sleep(2)
check.notify()
check.release()
time.sleep(2)
print ("func2 finished")
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
Here the condition variable is using a mutex internally to communicate between the threads; So only one thread can acquire the condition variable at a time. The first function acquires the condition variable and then releases it but registers that it is going to wait until it receives a notification via the condition variable. The second thread can then acquire the condition variable and, when it has done what it needs to do, it notifies the waiting thread that it can continue.

from threading import Thread
import time
check = False
def func1():
print ("funn1 started")
while True:
if check:
print ("got permission")
break
def func2():
global check
print ("func2 started")
time.sleep(2)
check = True
time.sleep(2)
check = False
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()

func1 must be like this
def func1():
print("func1 started")
while True:
if check:
print("got permission")
break
else:
time.sleep(0.1)

Related

How to populate a multiprocessing queue inside two processes and then operate on the queue in a third process?

I'd like to to create a multiprocessing queue that is populated in two separate processes and then further processed in a third process. By way of an MRE:
import multiprocessing as mp
from time import sleep
def add_one(queue: mp.Queue):
print("I am in add_one")
while True:
print("Adding one")
queue.put(1)
sleep(1)
def add_two(queue: mp.Queue):
print("I am in add_two")
while True:
print("Adding two")
queue.put(2)
sleep(2)
def print_number(queue: mp.Queue):
print("I am in print_number")
while True:
if not queue.empty():
print(queue.get(), end=",")
sleep(0.5)
def run():
queue = mp.Queue()
add_one_process = mp.Process(target=add_one, args=(queue,))
add_two_process = mp.Process(target=add_two, args=(queue,))
print_process = mp.Process(target=print_number, args=(queue,))
add_one_process.start()
add_two_process.start()
print_process.start()
add_one_process.join()
add_two_process.join()
print_process.join()
if __name__ == "__main__":
run()
The print statements inside add_one and add_two execute but the print statement inside the print_number function never executes.
However, if I amend the print_number function to:
def print_number(queue: mp.Queue):
print("I am in print_number")
while True:
if not queue.empty():
print("Printing queue item")
print(queue.get(), end=",")
sleep(0.5)
Then both print statements execute. Why is this happening?

How to keep executing code until another function returns value?

from time import sleep
def foo():
sleep(3)
return True
while True:
print('Running')
if foo() == True:
print('Finished.')
break
I want to keep printing "Running" but when foo returns True I want to print "Finished" (once) and break out of the loop.
I have tried the above but it prints "Running" just once and waits for foo to finish executing and then continues.
import threading
from time import sleep
flag = True
def foo()->None:
global flag
sleep(1)
flag = False
if __name__ == "__main__":
t1 = threading.Thread(target=foo)
t1.start()
while flag:
print('Running')
print('Finished')
Because you worked with only one thread, when you call the function the main stops until the function returns.
Therefore, if you want the main code and the function to run together, you have to work with threads.
So, after trying somethings I found 2 solutions, of my own question, that uses threading.
1. Modifies the foo function
from time import sleep
from threading import Thread
x = True
def foo():
sleep(3)
global x
x = False
print('finished')
def printing():
while x:
print('Running')
foo_thread = Thread(target=foo)
foo_thread.start()
printing_thread = Thread(target=printing)
printing_thread.start()
2. Uses decorator to keep foo unchanged
from time import sleep
from threading import Thread
x = True
def sets_true(func):
def wrapper():
returned_value = func()
global x
x = False
print('finished')
return wrapper
#sets_true
def foo():
sleep(3)
return True
def printing():
while x:
print('Running')
foo_thread = Thread(target=foo)
foo_thread.start()
printing_thread = Thread(target=printing)
printing_thread.start()

communication between two multiprocessing in real time

I have 2 processing, I need that when something happened on one process, something else will happen on the other.
For example:
import multiprocessing
def function_1(num):
while True:
status = False
for i in range (num):
if i == 100:
status = True
i +=1
def function_2():
while True:
if status == True:
print("status changed")
if __name__ == '__main__':
num = 101
a = multiprocessing.Process(target=function_1,args=(num,))
b = multiprocessing.Process(target=function_2)
a.start()
b.start()
a.join()
b.join()
This code obviously does not work, how can I make it work? I don't need one process to end and then get the result, I need the process to continue after that... is there a way to do that?
thank you!
Instead of a using a shared variable, for the purpose of making function_2 wait until function_1 reaches a certain state, you can create a multiprocessing.Queue instance to pass to both functions, and take advantage of the fact that Queue.get blocks until the queue receives something to dequeue, and make function_1 put something into the queue once it reaches the desired state:
import multiprocessing
def function_1(queue, num):
while True:
for i in range(num):
print(i)
if i == 3:
queue.put(None)
def function_2(queue):
queue.get()
print('do something')
if __name__ == '__main__':
num = 5
queue = multiprocessing.Queue()
a = multiprocessing.Process(target=function_1, args=(queue, num))
b = multiprocessing.Process(target=function_2, args=(queue,))
a.start()
b.start()
You forgot to add .join() after the start().
Try this :
a.start()
b.start()
a.join()
b.join()

What is the correct way to control threads?

I need run 3 or 5 threads approx, this threads monitoring some activities in the OS. Because of this, the main program must be running in background. I've read many examples and explanations, but I'm not clear yet how to launch threads and main program in the background and after that, how to control them.
I start threads in daemon mode from main program:
import threading
import time
def fun1():
while True:
print("Thread 1")
time.sleep(1)
def fun2():
while True:
print("Thread 2")
time.sleep(1)
def fun3():
while True:
print("Thread 3")
time.sleep(1)
def main():
thread1 = threading.Thread(target=fun1)
thread1.daemon = True
thread1.start()
thread2 = threading.Thread(target=fun2)
thread2.daemon = True
thread2.start()
thread3 = threading.Thread(target=fun3)
thread3.daemon = True
thread3.start()
if __name__ == '__main__':
try:
main()
while True:
print("------------")
print("Main program")
print("------------")
time.sleep(3)
except (KeyboardInterrupt, SystemExit):
print("Terminated")
and after that I run the main program in background with (I'm not sure that this is the best way to do it for what I want to achieve):
python daemon_thread.py &
How control the threads after main program initialization if I need stop a specific thread, change its state, or whatever? How to access a specific thread or the main program?
I understand now how to do, to resume the problem: I have a main program running in background and this main program have some threads. But I want with another script or program stop the main program with the threads safetly and in some cases pause and resume threads.
I didn't have a correctly concept about how to use the Threads. I can stop or send signal to this threads from main program How?,with a database or config file.
I updated my project with this changes:
import threading
import time
import sqlite3
def fun1(stop_event1):
while not stop_event1.is_set():
print("Thread 1")
time.sleep(1)
def fun2(stop_event2):
while not stop_event2.is_set():
print("Thread 2")
time.sleep(1)
def fun3(stop_event3):
while not stop_event3.is_set():
print("Thread 3")
time.sleep(1)
def main():
stop_event1 = threading.Event()
thread1 = threading.Thread(target=fun1, args=(stop_event1,))
thread1.daemon = True
thread1.start()
stop_event2 = threading.Event()
thread2 = threading.Thread(target=fun2, args=(stop_event2,))
thread2.daemon = True
thread2.start()
stop_event3 = threading.Event()
thread3 = threading.Thread(target=fun3, args=(stop_event3,))
thread3.daemon = True
thread3.start()
while True:
print("------------")
print("Main program")
print("------------")
time.sleep(3)
if alive_main():
print("Finish Threads")
stop_event1.set()
stop_event2.set()
stop_event3.set()
print("Bye")
break
def alive_main():
conn = sqlite3.connect('example.db')
c = conn.cursor()
c.execute('SELECT alive_main FROM config')
row = c.fetchone()
if row[0] == 1:
return True
else:
return False
if __name__ == '__main__':
try:
main()
except (KeyboardInterrupt, SystemExit):
print("Terminated")
If I want change with another class or script the state of my threads, I just change config table in my database y this take effect in the Threads, from main function. In this example if I stop correctly my threads and program just I update table, that's it.
sqlite> UPDATE config SET alive_main = 1;
I need read about Signals and Condition Objects to complement correctly Threads uses.
Thanks everyone!

Stopping a thread once condition matches

I want to trigger upfunction and stop when it writes 3 in the filename. Basically I want to stop a thread once the condition is met as shown below.
def getstatus():
fh = open(filename,'r')
return fh.read()
def upfunction(arg):
for i in range(arg):
print ("backup running")
print(getstatus())
target = open(filename, 'w')
target.write(str(i))
sleep(1)
if __name__ == "__main__":
thread = Thread(target = upfunction, args = (10, ))
thread.start()
print(getstatus())
while getstatus() != "3":
print("NOT 3 ")
sleep(0.5)
continue
thread.stop()
print("thread finished...exiting")
It shows
AttributeError: 'Thread' object has no attribute 'stop'
Please see me as newbie to python.
Any help will be highly appreciated
'Thread' object has no attribute 'stop' is helpful answer from python interpretator to you
You should place thread termination condition to upfunction.
def upfunction(arg):
i = 0
while getstatus() != "3":
print ("backup running")
print(getstatus())
target = open(filename, 'w')
target.write(str(i))
i += 1
sleep(1)
if __name__ == "__main__":
thread = Thread(target = upfunction, args = (10, ))
thread.start()
print(getstatus())
print("thread finished...exiting")
you can just use threading deamon method to kill this new thread.
thread.start()
thread.deamon()
when the main threads ends this custom threads also dies .so there is no need of that.
Here are some explanation about the right way to do that: Is there any way to kill a Thread in Python?.
And as Lex said [0], you can add a condition (in upfunction arguments) to stop your target function.

Categories