harlowja / fasteners

A python package that provides useful locks.
Apache License 2.0
246 stars 45 forks source link

InterProcessLock behaves differently on Windows7 compared to Gnu-Linux. #29

Closed JackDca closed 3 years ago

JackDca commented 6 years ago

On Gnu-Linux (Debian stretch), Python 2.7.14, if InterProcessLock.acquire() is called and returns True, it can be called a second time from the same process and will return True the second time. This is true even if the second call is made using a second InterProcessLock object created using the same lock file. No matter how many times it is called, a single call to release() will allow other processes to acquire() successfully.

On Windows7, the second call to acquire(blocking=False) will return False. Even worse, after two calls to acquire(), a call to release will result in an exception "Unable to release an unacquired lock", yet further calls to acquire(blocking=False) will continue to return False. This behaviour continues even if a second InterProcessLock object is created using the same lock file.

I have not tested under Windows to determine what happens if two calls to acquire() are made from two different threads.

harlowja commented 6 years ago

So one point, https://github.com/harlowja/fasteners/blob/master/fasteners/process_lock.py#L62-L63

JackDca commented 6 years ago

The issue as described has nothing to do with multiple threads.

In my case, there are two modules in the code which must check that the lock has been acquired by my process. This is because it is not safe for another instance of the application (another process) to execute those modules at the same time. If another process has acquired the lock, my process terminates. I don't know in advance which module will execute first. So I call acquire(blocking=False) in each of those two modules. This works OK under Gnu-Linux. It doesn't work under Windows7; instead I have to create a global variable to record that the lock has been acquired, then check it so as to avoid attempting to acquire the lock a second time.

To put it differently, under Window7. when the an attempt to acquire() fails, there is no way to determine whether that is because another process has acquired the lock, or because the lock had already been acquired by my process.

harlowja commented 6 years ago

Do u want to submit a patch to make it work on windows 7; I don't currently have a windows 7 machine to test against and I'm guessing you do?

JackDca commented 6 years ago

I will take a look to see if I can figure it out, but on Windows I am really just a user, so that could be a long process! My test machine is a VM (Virtualbox). My desktop came with Windows 7 - I moved it to a VM when I installed Debian (the MS licence allows that).

Thanks for your work on fasteners!

harlowja commented 6 years ago

Ok, I do have a windows 10 box, but not windows 7; if it becomes to much of a pain in the ass for you to do it just let me know and I can try...

psarka commented 3 years ago

I repro'd this one on windows 10, there is a bug in our code.

The repro is simple (needs a windows machine):

from fasteners import InterProcessLock

l = InterPorcessLock('file')

l.acquire()
l.acquire(blocking=False)
l.release()

The bug is line 142 in process_lock.py, where we set self.acquired = False on a failure to acquire (even though it should remain True, as we still hold the lock, just failed to reenter recursively).