Search code examples
pythonpython-3.xpython-multiprocessing

How to terminate a process when other process finishes?


I have created three functions where on the first I have created a countdown timer and on the other two I find prime numbers. I am using multiprocessing to make them execute together. What I am trying to make it do is when the timer finishes the other two process will also terminate. The other two functions will keep searching for the prime numbers until the timer finishes e.g. if timer is set to 1 minute, the functions will keep searching for prime numbers for one minute.

Right now the code waits n seconds before checking for the next number. What I did is I passed from the countdown function to the other two the seconds when they reach 0 to terminate the loop inside the other two functions.

Here is my code:

import time
import sys
from multiprocessing import Process

def countdown(t): 
    while t:
        mins, secs = divmod(t, 60) 
        timer = '{:02d}:{:02d}'.format(mins, secs) 
        print(timer, end="\r") 
        time.sleep(1) 
        t -= 1

def isPrime1():
    f = open('results.txt','w')
    i = 2
    while countdown(t) != 0:
        c = 0;
        for j in range (1, (i + 1), 1):
            a = i % j
            if (a == 0):
                c = c + 1

        if c == 2:
            f.write(str(i))
            print(i)
            if countdown(t) == 0:
                break
        i = i + 1
    f.close()

def isPrime2():
    f = open('results1.txt','w')
    i = 2
    while countdown(t) != 0:
        mins, secs = divmod(t, 60)
        c = 0;
        for j in range (1, (i + 1), 1):
            a = i % j
            if (a == 0):
                c = c + 1

        if c == 2:
            f.write(str(i))
            print(i)
            if countdown(t) == 0:
                break
        i = i + 1
    f.close()

if __name__=='__main__':
    t = int(input("Seconds:"))
    p1 = Process(target=isPrime1())
    p1.start()
    p2 = Process(target=isPrime2())
    p2.start()
    p3 = Process(target=countdown(t))
    p3.start()

Solution

  • You want to use Events. They are a synchronization technique used for communication among processes, built on synchronization primitives like lock/mutex.

    Each process has its own assigned memory region where variables are allocated, so variables are not shared among different processes. This is one of the main differences between processes and threads (threads share the same memory). When you create (=fork) a process, the variables of the original (father) process are copied in the new process (child) memory region. So they will have the same value at the beginning, but changes done after the fork will not be seen by the other processes.

    In your case, every process has its own copy of the t variable and it doesn't see the changes that the other processes make to their copy.

    See this as an example program that does what you want using Events:

    import time
    from multiprocessing import Process, Event
    
    def countdown(event, t):
        while t:
            mins, secs = divmod(t, 60)
            timer = '{:02d}:{:02d}'.format(mins, secs)
            print(timer, end="\r")
            time.sleep(1)
            t -= 1
        # Set the event to notify the other processes
        event.set()
        print("Countdown done")
    
    def isPrime(event):
        # This loop ends when the countdown is over
        while not event.is_set():
            # Your code here
            pass
        print("Done!")
    
    if __name__=='__main__':
    
        t = int(input("Seconds:"))
        event = Event() # the event is unset when created
        p1 = Process(target=isPrime, args=(event,))
        p1.start()
        p2 = Process(target=isPrime, args=(event,))
        p2.start()
        p3 = Process(target=countdown, args=(event,t,))
        p3.start()
        p1.join()
        p2.join()
        p3.join()
    

    and this is the result:

    output

    P.S. You don't need to duplicate the code for the function. You can use the same function to run as many processes as you want. They will proceed independently. You should also use join to make the original process wait for the end of its children.