w128
w128

Reputation: 4928

How to properly ensure termination of a thread that is using a shared Lock?

In __main__, I create a new daemon thread to achieve a non-blocking processing on a shared state protected by a threading.Lock(). While everything works fine from the looks of it when the program is running, I sporadically get an exception when quitting the program, i.e. when the daemon thread is supposed to terminate:

'NoneType' object has no attribute 'acquire'

The code is roughly as follows:

mutex = threading.Lock()

def async_processing(shared):
    global mutex
    while True:
        sleep(1)
        mutex.acquire()
        try:
            shared.modify_state()
        finally:
            mutex.release()


if __name__ == '__main__':
    shared = SomeObject()

    thread = threading.Thread(target=async_processing, args=(shared,))
    thread.daemon = True
    thread.start()

    if user_enters_some_command_to_stdin:       
        mutex.acquire()
        try:
            shared.modify_state()
        finally:
            mutex.release()

I'm not really at home with Python and am thus maybe not doing this the way it's supposed to be done, but my guess is that somehow a context switch to the thread happens after mutex is no longer available. Is this hypothesis true?

What is the best way to handle this?

Upvotes: 1

Views: 88

Answers (1)

Sraw
Sraw

Reputation: 20224

I think the simplest way is adding a flag variable:

mutex = threading.Lock()
flag = True

def async_processing(shared):
    while flag:
        sleep(1)
        with mutex:
            shared.modify_state()


if __name__ == '__main__':
    shared = SomeObject()

    thread = threading.Thread(target=async_processing, args=(shared,))
    thread.start()

    if some_user_action:        
        with mutex:
            shared.modify_state()
    flag = False
    thread.join()  # wait for exit.

Upvotes: 1

Related Questions