Search code examples
pythonpython-multithreading

How to pass a boolean by reference across threads and modules


I have a boolean that I want to pass to different threads that are executing methods from different modules. This boolean acts as a cancellation token so if set, the thread should exit. It seems to be passed by value since if I set it in another thread it doesn't change in the other threads. Thanks.

import module2
from threading import Thread

cancellationToken = False

def main:
    thread2 = Thread(target = module2.method2, args (on_input, cancellationToken, ))
    thread2.start()
    ...
    thread2.join()

def on_input(command):
    global cancellationToken
    ...
    if(...):
        cancellationToken = True
    ...

method2 in module2 is just a simple infinite while loop that checks the cancellation token and responds to user input.

def method2(on_input, cancellationToken):
    while(True):
        if(cancellationToken):
            return
        ...
        on_input(...)

Solution

  • When you do this:

    thread2 = Thread(target = module2.method2, args (on_input, cancellationToken, ))
    

    You're essentially passing the value False for the 2nd argument to the thread method.

    But when you do this after that:

    cancellationToken = True
    

    You're replacing the reference represented by cancellationToken, but not the value that was originally passed to thread2.

    To achieve what you want to do, you'll need to create a mutable object wrapper for your cancellation state:

    class CancellationToken:
       def __init__(self):
           self.is_cancelled = False
    
       def cancel(self):
           self.is_cancelled = True
    
    cancellationToken = CancellationToken()
    
    thread2 = Thread(target = module2.method2, args (on_input, cancellationToken, ))
    
    # then later on
    cancellationToken.cancel()
    

    Your thread code becomes:

    def method2(on_input, cancellationToken):
        while(True):
            if(cancellationToken.is_cancelled):
                return
            ...
            on_input(...)