0

So, as you can see below, I've got two processes, t1 and t2, but I want t2 to terminate when t1's break condition is met and vice versa. Right now my solution isn't working, can anyone tell me why?

def distance1():
    while True:
        dist = distance(TRIG1, ECHO1)
        if dist < 0.6 or dist > 6.5:
            print("Nichts")
        elif dist > 0.6 or dist < 6.5:
            print("Entfernung1 = %.1f cm" % dist)
            lcd.lcd_display_string("Achtung! Radfahr-",1)
            lcd.lcd_display_string("rer beachten!",2)
            break

def distance2():
    while break2==False:
        dist2 = distance(TRIG2, ECHO2)
        if dist2 < 0.6 or dist2 > 6.5:
            print("Nichts2")
        elif dist2 > 0.6 or dist2 < 6.5:
            print("Entfernung2 = %.1f cm" % dist2)
            time.sleep(8)
            lcd.lcd_clear()
            break4=True
            break


def distance4():
    while break4==False:
        dist4 = distance(TRIG4, ECHO4)
        if dist4 < 3.0 or dist4 > 12.0:
            print("Nichts4")
        elif dist4 > 3.0 or dist4 < 12.0:
            print("Entfernung4 = %.1f cm" % dist4)
            lcd.lcd_display_string("Stop! Radfahrer ",1)
            lcd.lcd_display_string("  durchlassen!",2)
            for x in range(0, 8):
                GPIO.output(LED, GPIO.HIGH)
                time.sleep(1)
                GPIO.output(LED, GPIO.LOW)
                time.sleep(1)
            lcd.lcd_clear()
            break2=True
            break


t1=Process(target=distance2)
t2=Process(target=distance4)

distance1()
t1.start()
t2.start()

EDIT: Sorry for constantly changing my question, but I'd like to do it with a global variable.

3 Answers3

1

(Update: this is an answer to the question before it was changed and is about multiprocessing)

You should use t1.terminate() when another one gave you a result. Or you can use TerminateProcess()


Update 2

While there is a _stop function to stop a thread, it shouldn't be used because all threads share resources and you can end up in a broken state.


Update 3

Your variable aren't global, to make them global use global break4 in the beginning of the function and define them globally before starting the threads.

Benoît P
  • 3,179
  • 13
  • 31
  • I've already tried this (which is my why my original question still used multiprocessing) but it returned an error. –  Feb 14 '19 at 22:59
  • Threads aren't executed in parallel in Python and you shouldn't use them in the first place in this case. (Edit: I see you added `sleep` so it should work) – Benoît P Feb 14 '19 at 23:00
  • I'll try this again and see if it gets me somewhere, thanks for quickly answering my question! –  Feb 14 '19 at 23:05
  • I updated my answer on why you can't kill Threads like Processes – Benoît P Feb 14 '19 at 23:17
  • Yeah, which is why was actually looking for a way to terminate the thread using a global variable. –  Feb 14 '19 at 23:18
  • Ok I've updated my answer, Sorry that I didn't understand your problem – Benoît P Feb 14 '19 at 23:22
  • Thanks a lot for helping me out there! –  Feb 14 '19 at 23:25
1

There are a few facts to keep in mind:

  1. you cannot preemptively terminate a thread. If you want to preemptively terminate, you have to use processes. Or use cooperative termination, which works with both multiprocessing and threading, but read the second point for some caveats

  2. most objects are not shared by default if you use multiprocessing, they'll be forked so that each process get its own copy. Processes don't see each other's modifications. If you want to share variables, you need to use shared memory, for example by using multiprocessing.Value() or multiprocessing.Manager(). For more complex program, it's best to use message passing with multiprocessing.Queue().

  3. global variables are shared if you use threading, which means that even though threading.Thread and multiprocessing.Process have similar interfaces, most programs may not work correctly when ported from one to the other without further modifications

For the general case, you might want to use multiprocessing.Value()/Array() to share values between multiprocessing processes.

For your particular use case of setting a boolean termination flags, you can get by using multiprocessing.Event() or multiprocessing.Condition() variables. These are high level constructs for implementing many cooperative situations between multiple threads/processes.

Lie Ryan
  • 62,238
  • 13
  • 100
  • 144
0

You could introduce either a global variable or class-property to control execution of your loops:

import threading
import time

class Program():
    run = True

    def distance1(self):
        while self.run:
            print("distance1")
            time.sleep(0.1)

    def distance2(self):
        while self.run:
            print("distance2")
            time.sleep(1)
            self.run = False
    def distance4(self):
        while self.run:
            print("distance4")
            time.sleep(0.1)

p = Program()
t1=threading.Thread(target=p.distance2)
t2=threading.Thread(target=p.distance4)

t1.start()
t2.start()
p.distance1()

Here I kill all 3 loops from distance2 with self.run = False.

There's a lot of good information in this thread: Is there any way to kill a Thread? and this answer concerning multiprocessing.Process.

Edit: Global variable is pretty much the same, just remember global run in the functions to ensure the global run variable is altered, instead of initiating a new variable locally in the functions:

import threading
import time

run = True

def distance1():
    global run
    while run:
        print("distance1")
        time.sleep(0.1)

def distance2():
    global run
    while run:
        print("distance2: " + str(run))
        time.sleep(1)
        run = False
def distance4():
    global run
    while run:
        print("distance4")
        time.sleep(0.1)

t1=threading.Thread(target=distance2)
t2=threading.Thread(target=distance4)

t1.start()
t2.start()
distance1()
Jeppe
  • 1,830
  • 3
  • 24
  • 33