Search code examples
pythonmultithreadingthreadpooldeadlock

deadlock with ThreadPoolExecutor when trying to run 2 blocking functions


I'm trying to run 2 different blocking functions, that utilize the same global variable a.

the code:

from concurrent.futures import ThreadPoolExecutor, as_completed
import keyboard

a = 0

def incA():
    global a
    while True:
        print(f'inc a: {a} -> {a+1}')
        a+=1
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            break
        
        
def printA():
    # a is read-only
    while True:
        print(f'print a: {a}')
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            break
        
        
with ThreadPoolExecutor(max_workers=2) as executor:
    f1 = executor.submit(incA())
    f2 = executor.submit(printA())

when I try to run this piece of code i get a deadlock. the output:

inc a: 15640 -> 15641
inc a: 15641 -> 15642
inc a: 15642 -> 15643
inc a: 15643 -> 15644
inc a: 15644 -> 15645
inc a: 15645 -> 15646
inc a: 15646 -> 15647
inc a: 15647 -> 15648
inc a: 15648 -> 15649
inc a: 15649 -> 15650
inc a: 15650 -> 15651
inc a: 15651 -> 15652
inc a: 15652 -> 15653
print a: 15653  

how can I fix this to make my code run asynchronously, for it to have an output that looks like this:

.
.
.
inc a: 15640 -> 15641
print a: 15641
inc a: 15641 -> 15642
print a: 15642
inc a: 15642 -> 15643
print a: 15643
.
.
.

Solution

  • When you call submit, you're including the parenthesis on the functions:

    f1 = executor.submit(incA())
    f2 = executor.submit(printA())
    

    So instead of passing the function object, you're executing the function once and passing in the result, except that incA() never returns, so you never actually submit anything.

    Just remove the parenthesis:

    f1 = executor.submit(incA)
    f2 = executor.submit(printA)