Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected behavior when using python thread locks and circulair imports

I wrote a simple test program using thread locks. This program does not behave as expected, and the python interpreter does not complain.

test1.py:

from __future__ import with_statement
from threading import Thread, RLock
import time
import test2

lock = RLock()

class Test1(object):
    def __init__(self):
        print("Start Test1")
        self.test2 = test2.Test2()
        self.__Thread = Thread(target=self.myThread, name="thread")
        self.__Thread.daemon = True
        self.__Thread.start()
        self.test1Method()

    def test1Method(self):
        print("start test1Method")
        with lock:
            print("entered test1Method")
            time.sleep(5)
            print("end test1Method")

    def myThread(self):
        self.test2.test2Method()

if __name__ == "__main__":
    client = Test1()
    raw_input()

test2.py:

from __future__ import with_statement
import time
import test1

lock = test1.lock

class Test2(object):
    def __init__(self):
        print("Start Test2")

    def test2Method(self):
        print("start test2Method")
        with lock:
            print("entered test2Method")
            time.sleep(5)
            print("end test2Method")

Both sleeps are executed at the same time! Not what I expected when using the lock.

When test2Method is moved to test1.py everything works fine. When I create the lock in test2.py and import it in test1.py everything works fine. When I create the lock in a separate source file and import it both in test1.py and test2.py everything works fine.

Probably it has to do with circulair imports.

But why doesn't python complain about this?

like image 622
user1997293 Avatar asked Oct 05 '22 07:10

user1997293


1 Answers

In Python when you execute a python script using $ python test1.py what happen is that your test1.py will be imported as __main__ instead of test1, so if you want to get the lock defined in the launched script you shouldn't import test1 but you should import __main__ because if you do the first one you will create another lock that is different from the __main__.lock (test1.lock != __main__.lock).

So one fix to your problem (which far from being the best) and to see what is happening you can change your 2 script to this:

test1.py:

from __future__ import with_statement
from threading import Thread, RLock
import time

lock = RLock()

class Test1(object):
    def __init__(self):
        print("Start Test1")
        import test2    # <<<<<<<<<<<<<<<<<<<<<<<< Import is done here to be able to refer to __main__.lock.
        self.test2 = test2.Test2()
        self.__Thread = Thread(target=self.myThread, name="thread")
        self.__Thread.daemon = True
        self.__Thread.start()
        self.test1Method()

    def test1Method(self):
        print("start test1Method")
        with lock:
            print("entered test1Method")
            time.sleep(5)
            print("end test1Method")

    def myThread(self):
        self.test2.test2Method()

if __name__ == "__main__":
    client = Test1()
    raw_input()

test2.py:

from __future__ import with_statement
import time
# <<<<<<<<<<<<<<<<<<<<<<<<<<<<< test1 is changed to __main__ to get the same lock as the one used in the launched script.
import __main__

lock = __main__.lock

class Test2(object):
    def __init__(self):
        print("Start Test2")

    def test2Method(self):
        print("start test2Method")
        with lock:
            print("entered test2Method")
            time.sleep(5)
            print("end test2Method")

HTH,

like image 92
mouad Avatar answered Oct 11 '22 01:10

mouad