Running two function together with multiprocessing and share variables - python

i used multiprocessing but i don't know how to do it
the logic : a variable sign is equal to 0, with a function called timer count 20 seconds and each second check if sign is equal to 1 then it'll print something and breaks the loop, at the same time with a function called waiting waits for an input from another library as example "discord" or "socket" so if the input is equal to my key flip the variable sign to 1 and that affects the first function timer
import multiprocessing
from time import sleep
sign = 0
def timer():
for s in range(20):
if sign == 1: # if the input is equal to the secret key then break the timer
print("Yes!")
break
else:
sleep(1) #if not then continue timing
def waiting():
# maybe it waits for an input or a message from "discord or whatsapp"
if message == "secret_key":
sign = 1
p1 = multiprocessing.Process(target=timer)
p2 = multiprocessing.Process(target=waiting)
p1.start()
p2.start()

I mentioned it above in a comment, but here is how you would use an event
import time
import multiprocessing as mp
def timer(exit_event):
for s in range(20):
if exit_event.is_set():
print("Yes!")
break
else:
time.sleep(1) #if not then continue timing
def waiting(exit_event):
# maybe it waits for an input or a message from "discord or whatsapp"
time.sleep(5)
exit_event.set()
if __name__ == '__main__':
exit_event = mp.Event()
p1 = mp.Process(target=timer, args=(exit_event,))
p2 = mp.Process(target=waiting, args=(exit_event,))
p1.start()
p2.start()
p1.join()
p2.join()
However the real way to use an Event is to just to wait() for it to become true. No need for a sleep loop.
def timer(exit_event):
if exit_event.wait(timeout=20)
# returns True if the event is True. False if timed out
print("Yes!")

Related

Stopping a thread after a certain amount of time while keeping the main thread responsive

I'm looking to terminate a thread after a certain amount of time. The thread is called from an infinite while loop that waits for users input. Thread starts after user inputs number 4 from command line, after which thread writes some text to the console in another infinite loop. After x amount of time the started thread should terminate. How can I make the thread stop after the set time while keeping the main thread with user input responsive (active)?
Here is some sample code:
def loop():
while True:
print("ON")
print("OFF")
if __name__ == "__main__":
t = threading.Thread(target=loop)
try:
while True:
print(">>", end='')
command = int(input())
if command == 1:
...
elif command == 2:
...
elif command == 3:
...
elif command == 4:
print("Insert time:")
time = float(input())
t.start()
elif command == 5:
...
It is possible to pass an argument to the loop and that can be used to stop the thread, something like this:
def loop(running):
while running[0]:
print("HELLO")
if __name__ == "__main__":
running = [True]
t = threading.Thread(target=loop, args=(running,))
t.start()
while True:
command = input()
running[0] = False
running is shared by both the main thread and the other thread, so changing the value in one changes it in the other.

How to close all the processes one by one in a program that operates with multiprocessing by means of an 'if' validation found in one of them process?

import multiprocessing
from threading import Thread
import speech_recognition as sr
def actions_func(conn1_3,conn2_3):
def capture_cam(conn1, conn1b):
def audio_listening(conn2, conn2b):
global catch_current_frame
catch_current_frame = False
# start dameon thread to handle frame requests:
Thread(target=handle_catch_current_frame_requests, args=(conn2,), daemon=True).start()
Thread(target=handle_cam_activate_requests, args=(conn2b,), daemon=True).start()
while True:
r = sr.Recognizer()
with sr.Microphone() as source:
catch_current_frame = False
r.adjust_for_ambient_noise(source)
print("Please say something...")
audio = r.listen(source)
try:
text = r.recognize_google(audio, language="es-ES")
print("You have said: \n " + repr(text))
#Verifications
if text.lower() == "capture":
catch_current_frame = True
elif text.lower() == "Close your program":
#This is where I need to close processes p1, p2 and p3
break
else:
pass
except Exception as e:
print("Error : " + str(e))
def main_process(finish_state):
conn1, conn1_3 = multiprocessing.Pipe(duplex=True)
conn2, conn2_3 = multiprocessing.Pipe(duplex=True)
conn1b, conn2b = multiprocessing.Pipe(duplex=True)
#Process 1
p1 = multiprocessing.Process(target=capture_cam, args=(conn1, conn1b, ))
p1.start()
#Process 2
p2 = multiprocessing.Process(target=audio_listening, args=(conn2, conn2b, ))
p2.start()
#Process 3
p3 = multiprocessing.Process(target=actions_func, args=(conn1_3 ,conn2_3 ,))
p3.start()
if __name__ == '__main__':
finish_state = multiprocessing.Event()
main_process(finish_state)
print("continue the code... ")
I need that when the variable text is equal to "Close your program" the 3 active processes(p1,p2,p3) are closed.
I have tried to do something like this:
elif text.lower() == "Close your program":
print("the process has been interrupted!")
finish_state.set()
for process in [p1, p2, p3]:
process.terminate()
But it is not working for me, and I would need a better code that allows me to close them one by one in that code block if text is equal to "Close your program".
What should I do so that under that condition all the processes are closed one by one?
You could try the following Event-based solution (but there are even simpler solutions to follow):
Have main_process pass to audio_listening an additional argument, finish_state:
def main_process():
conn1, conn1_3 = multiprocessing.Pipe(duplex=True)
conn2, conn2_3 = multiprocessing.Pipe(duplex=True)
conn1b, conn2b = multiprocessing.Pipe(duplex=True)
#Process 1
p1 = multiprocessing.Process(target=capture_cam, args=(conn1, conn1b, ))
p1.start()
#Process 2
finish_state = multiprocessing.Event()
p2 = multiprocessing.Process(target=audio_listening, args=(conn2, conn2b, finish_state))
p2.start()
#Process 3
p3 = multiprocessing.Process(target=actions_func, args=(conn1_3 ,conn2_3 ,))
p3.start()
finish_state.wait()
p1.terminate()
p2.terminate() # Not really necessary since the process is ending by itself
p3.terminate()
if __name__ == '__main__':
main_process()
Note that it is now main_process that is creating the finish_state multiprocessing.Event instance; there appears to be no need for it to be passed as an argument. When the event is set, the main process will terminate the subprocesses that it has created.
Then in audio_processing:
def audio_listening(conn2, conn2b, finish_state):
...
if text.lower() == "capture":
catch_current_frame = True
elif text.lower() == "Close your program":
# Set the finish state event:
finish_state.set()
break
There are even two simpler alternatives that do not even require an Event variable:
The audio_process process is in an infinite loop until it either gets a "Close your program" message or it gets an exception. In both cases it terminates and presumably we then want the other two processes to terminate, also. Therefore, the main process can just issue a call to p2.join() after it has started all the other processes in order to wait for the audio_process process to complete and then either:
Call p1.terminate() followed by p3.terminate().
Or start processes p1 and p3 specifying daemon=True, e.g. p1 = multiprocessing.Process(target=capture_cam, args=(conn1, conn1b), daemon=True). Being daemon processes they will now automatically terminate as soon as the main process terminates. Therefore, there is no need to call terminate on these processes.

Python - creating a simple killswitch for a function that runs with multiprocessing

So, i would claim that i understand how Asyncio, Multiprocessing, Threading etc. works, basically. I know how to listen for keystrokes too - there are many good examples on this site.
However i was unable to combine both into one. I have a programm that runs continously in a loop, until it runs into certain cases where it stops. In these cases, it uses a Multiprocessing.Queue() to prompt for user input on wether it should continue or not.
All of this works, so far so good. Now i want to add a second catch case here: The programm should, once it starts running, immediatly cease working as soon as i press a certain button (lets say Escape).
This is the very dumbed down version of my programm:
test.py:
from test3 import Counter
from multiprocessing import Process, Queue
import sys
def main(q, passed_variable):
foo = Counter()
p1 = Process(target=foo.counting, args=(q,passed_variable))
p1.start()
p1.join()
if q.get() == False:
x = input("Keep going?")
print(x)
if x == "y":
main(q, user_Input)
else:
sys.exit()
if __name__ == "__main__":
q = Queue()
user_Input = ("What you want from me, man?")
print("Starting")
main(q, passed_variable=user_Input)
test3.py:
import time
class Counter:
def counting(self, q, user_input):
x = 0
while True:
print(str(x) + " " + user_input)
if x == 4:
q.put(False)
break
time.sleep(1)
x += 1
I tried everything i could think of, in no case did i get the desired result, and no question i found here was able to help me in this specific case.
You can solve this using keyboard and then creating a second Queue():
from test3 import Counter
from multiprocessing import Process, Queue
import sys
import keyboard
def main(q, queue2, passed_variable):
foo = Counter()
p1 = Process(target=foo.counting, args=(q,passed_variable))
p1.start()
p2 = Process(target=keyCatcher, args=(queue2,))
p2.start()
if queue2.get() == False:
p1.terminate()
print("Terminating Programm")
sys.exit()
if q.get() == False:
x = input("Keep going?")
print(x)
if x == "y":
main(q, queue2, user_Input)
else:
sys.exit()
def keyCatcher(queue2):
while True:
if keyboard.is_pressed('q'): # if key 'q' is pressed
queue2.put(False)
if __name__ == "__main__":
q = Queue()
queue2 = Queue()
user_Input = ("What you want from me, man?")
print("Starting")
main(q, queue2, passed_variable=user_Input)
The crux is:
p1.start()
p1.join()
Which means after main() starts p1, it waits for it to finish. So there's no chance to interrupt it while processing.
You need to:
wait for p1 to finish
while waiting, see if the main process gets a 'q'
if the main process gets a 'q', stop it.
Something like:
p1.start()
while p1.is_alive():
k = keyboard.read_key()
if k == 'q':
p1.terminate()

How to ask Question by if statement via timeout

is there any way for ask question by if statement and after afew sec if user didnot give any answer , if state use a default answer?
inp = input("change music(1) or close the app(2)")
if inp = '1':
print("Music changed)
elif inp = '2':
print("good by")
in this case if user dont give any answer after 30 sec by default if statement choose number 3
from threading import Timer
out_of_time = False
def time_ran_out():
print ('You didn\'t answer in time') # Default answer
out_of_time = True
seconds = 5 # waiting time in seconds
t = Timer(seconds,time_ran_out)
t.start()
inp = input("change music(1) or close the app(2):\n")
if inp != None and not out_of_time:
if inp == '1':
print("Music changed")
elif inp == '2':
print("good by")
else:
print ("Wrong input")
t.cancel()
Timer Objects
This class represents an action that should be run only after a certain amount of time has passed — a timer. Timer is a
subclass of Thread and as such also functions as an example of
creating custom threads.
Timers are started, as with threads, by calling their start() method.
The timer can be stopped (before its action has begun) by calling the
cancel() method. The interval the timer will wait before executing its
action may not be exactly the same as the interval specified by the
user.
For example:
def hello():
print("hello, world")
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
class threading.Timer(interval, function, args=None, kwargs=None)
Create a timer that will run function with arguments args and keyword
arguments kwargs, after interval seconds have passed. If args is None
(the default) then an empty list will be used. If kwargs is None (the
default) then an empty dict will be used.
cancel()
Stop the timer, and cancel the execution of the timer’s action. This will only work if the timer is still in its waiting
stage.
Here's an alternative way to do it (python 3), using multiprocessing. Note, to get the stdin to work in the child process, you have to re open it first. I'm also converting the input from string to int to use with the multiprocessing value, so you might want to error check there as well.
import multiprocessing as mp
import time
import sys
import os
TIMEOUT = 10
DEFAULT = 3
def get_input(resp: mp.Value, fn):
sys.stdin = os.fdopen(fn)
v = input('change music(1) or close the app (2)')
try:
resp.value = int(v)
except ValueError:
pass # bad input, maybe print error message, try again in loop.
# could also use another mp.Value to signal main to restart the timer
if __name__ == '__main__':
now = time.time()
end = now + TIMEOUT
inp = 0
resp = mp.Value('i', 0)
fn = sys.stdin.fileno()
p = mp.Process(name='Get Input', target=get_input, args=(resp, fn))
p.start()
while True:
t = end - time.time()
print('Checking for timeout: Time = {:.2f}, Resp = {}'.format(t, resp.value))
if t <= 0:
print('Timeout occurred')
p.terminate()
inp = DEFAULT
break
elif resp.value > 0:
print('Response received:', resp.value)
inp = resp.value
break
else:
time.sleep(1)
print()
if inp == 1:
print('Music Changed')
elif inp == 2:
print('Good Bye')
else:
print('Other value:', inp)

How to stop and start a thread at will

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)

Categories