Python threading lock not working in simple example

I need to be missing something, but this simple example of two threads trying to change a global variable in a function does not give the expected result:

from threading import Thread, Lock
some_var = 0

def some_func(id):
    lo = Lock()
    with lo:
        global some_var
        print("{} here!".format(id))
        for i in range(1000000):
            some_var += 1
        print("{} leaving!".format(id))


t1 = Thread(target=some_func, args=(1,))
t2 = Thread(target=some_func, args=(2,))
t1.start()
t2.start()
t1.join()
t2.join()
print(some_var)

      

outputs:

1 here!
2 here!
2 leaving!
1 leaving!
1352010

      

As you can see both threads are entering the part that needs to be blocked at the same time and the increment of the globel variable 'some_var' gets mixed up because of this.

It looks like Lock doesn't work for some reason. For a range up to 10,000 it works, but that's probably only because the GIL is not being released during such short computations.

What's happening?

I am using Python3.3.2 64bit

+3


source to share


3 answers


The function Lock()

creates a completely new lock - one that only the thread calling the function can use. This is why it doesn't work, because each thread blocks a completely different lock.

Blocking elements are one of the few things you can declare as global without any problem, because you absolutely want every thread to see the same thing Lock()

. You should try this instead:



from threading import Thread, Lock
some_var = 0
lo = Lock()

def some_func(id):
    global lo
    with lo:
        global some_var
        print("{} here!".format(id))
        for i in range(1000000):
            some_var += 1
        print("{} leaving!".format(id))

      

+5


source


Each time you call your function, a new lock is created, so you will have different locks for each thread. The Lock object must be created globally, because every thread must be able to see the same lock held by another. Try moving the lock object creation as a global lock!



+3


source


Or you can define a lock in your main () function. And pass it to the called function.

lock = threading.Lock()
t1 = Thread(target=some_func, args=(1,lock))
t2 = Thread(target=some_func, args=(2,lock))
t1.start()
t2.start()

      

Thus, there is only one lock. It's best to avoid globals whenever possible.

0


source







All Articles