Ad

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?

Ad

Answer

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_statemultiprocessing.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:

  1. Call p1.terminate() followed by p3.terminate().
  2. 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.
Ad
source: stackoverflow.com
Ad