ARN
ARN

Reputation: 31

How to change argument value in a running thread in python

How do I change a parameter of a function running in an infinite loop in a thread (python)? I am new to threading and python but this is what I want to do (simplified),

class myThread (threading.Thread):
   def __init__(self, i):
       threading.Thread.__init__(self)

   def run(i):
       self.blink(i)

   def blink(i):   
       if i!=0:
           if i==1:
               speed=0.10
           elif i==2:
               speed=0.20
           elif i==3:
               speed=0.30    

           while(true):
               print("speed\n")

i=3
blinkThread=myThread(i)
blinkThread.start()

while(i!=0):
i=input("Enter 0 to Exit or 1/2/3 to continue\n")
if i!=0:
   blinkThread.run(i)

Now, obviously this code gives errors regarding the run() method. I want to run the function blink() in infinite loop but change the 'i' variable. I also cannot do it without a thread because I have other portions of code which are doing parallel tasks. What can I do? Thanks!

Upvotes: 3

Views: 12873

Answers (2)

Daniel
Daniel

Reputation: 42758

Best thing to learn first, is to never change variables from different threads. Communicate over queues:

import threading
import queue

def drive(speed_queue):
    speed = 1
    while True:
        try:
            speed = speed_queue.get(timeout=1)
            if speed == 0:
                break
        except queue.Empty:
            pass
        print("speed:", speed)

def main():
    speed_queue = queue.Queue()
    threading.Thread(target=drive, args=(speed_queue,)).start()
    while True:
        speed = int(input("Enter 0 to Exit or 1/2/3 to continue: "))
        speed_queue.put(speed)
        if speed == 0:
            break

main()

Upvotes: 7

zwer
zwer

Reputation: 25789

Besides a lot of syntax errors, you're approaching the whole process wrong - there is no point in delegating the work from run to another method, but even if there was, the last while would loop infinitely (if it was actually written as while True:) never checking the speed change.

Also, don't use run() method to interface with your thread - it's a special method that gets called when starting the thread, you should handle your own updates separately.

You should also devote some time to learn OOP in Python as that's not how one makes a class.

Here's an example that does what you want, hope it might help you:

import threading
import time


class MyThread (threading.Thread):

    def __init__(self, speed=0.1):
        self._speed_cache = 0
        self.speed = i
        self.lock = threading.RLock()
        super(MyThread, self).__init__()

    def set_speed(self, speed):  # you can use a proper setter if you want
        with self.lock:
            self.speed = speed

    def run(self):
        while True:
            with self.lock:
                if self.speed == 0:
                    print("Speed dropped to 0, exiting...")
                    break
                # just so we don't continually print the speed, print only on change
                if self.speed != self._speed_cache:
                    print("Current speed: {}".format(self.speed))
                    self._speed_cache = self.speed
            time.sleep(0.1)  # let it breathe

try:
    input = raw_input  # add for Python 2.6+ compatibility
except NameError:
    pass

current_speed = 3  # initial speed

blink_thread = MyThread(current_speed)
blink_thread.start()

while current_speed != 0:  # main loop until 0 speed is selected
    time.sleep(0.1)  # wait a little for an update
    current_speed = int(input("Enter 0 to Exit or 1/2/3 to continue\n"))  # add validation?
    blink_thread.set_speed(current_speed)

Also, do note that threading is not executing anything in parallel - it uses GIL to switch between contexts but there are never two threads executing at absolutely the same time. Mutex (lock) in this sense is there just to ensure atomicity of operations, not actual exclusiveness.

If you need something to actually execute in parallel (if you have more than one core, that is), you'll need to use multiprocessing instead.

Upvotes: 1

Related Questions