Jesh Kundem Jesh Kundem - 3 months ago 6
Python Question

Stop the thread from inside the target function?

Is there a way that I can stop the thread after few seconds (INTERNALLY)

t1 = Thread(target=call_script1, args=())
t2 = Thread(target=call_script2, args=())
t3 = Thread(target=call_script3, args=())

t1.start()
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()


The Main program waits until thread returns. I would like to know if there is a way - when I spawn a thread - say t2, it targets a function - call_script2. Lets say that function takes like 5 seconds to run completely. I would like to know if I can return the thread say like after 3 seconds.

The ability of the thread to return after 3 seconds should be inside the call_script2 function. I believe having stop_event.wait(3) in the main thread does not work.

call_script2 function looks something like this.

def InterfaceThread2():
a = 1;
d = 2
i = 1
while i ==1:
#ser = serial.Serial(3, 115200)
if ser.isOpen():
ser.write('\x5A\x03\x02\x00\x02\x07')

a = ser.read(7) #### THIS COMMAND WAITS UNTIL IT RECEIVES DATA FROM MCU
## This usually happens in 100ms in theory. If it is taking like more than 100ms -for safety say I will wait for three seconds and if it did not respond back
## I want to stop the thread and popup an error message.

# Tell the GUI about the Information
wx.CallAfter(pub.sendMessage, "APP_EVENT2", arg1 = a, arg2 = d)
print "hello"

time.sleep(1)
i = i+1

Answer

I think you can get the behavior you want by using the timeout parameter available on the serial.Serial() constructor. Additionally, you'll need to protect your interactions with the Serial instance with a threading.Lock(), so that your threads don't step on each other as they read/write data:

ser = serial.Serial(..., timeout=3, ...)
lock = Threading.Lock()

def call_script1():
    a = 1
    d = 2
    i = 1
    while i == 1:  # Lock is acquired here
        with lock:
            if ser.isOpen():
                ser.write('\x5A\x03\x02\x00\x02\x07')
                a = ser.read(7)
                if len(a) != 7:
                    # We didn't get all the bytes we wanted, a timeout
                    # must have occurred.
                    print("Only read {} bytes!".format(len(a)))
                    # Maybe exit or throw an exception?

        # Lock is released here.
        # Tell the GUI about the Information
        wx.CallAfter(pub.sendMessage, "APP_EVENT2", arg1 = a, arg2 = d)
        print "hello"

        time.sleep(1)
        i = i+1

def call_script2():
    while i == 1:
        with lock:
            if ser.isOpen():
                # Do whatever

def call_script3():
    while i == 1:
        with lock:
            if ser.isOpen():
                # Do whatever

t1 = Thread(target=call_script1, args=())
t2 = Thread(target=call_script2, args=())
t3 = Thread(target=call_script3, args=())

t1.start()
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()