0

My use case: I want to call fcntl.flock() on a file but have a timeout. Following the recipe in Timeout on a function call, I wrapped my code in a contextmanager that implements timeouts via a Unix signal:

@contextmanager
def doTimeout(seconds):
    """Creates a "with" context that times out after the
    specified time."""
    def timeout_handler(signum, frame):
        pass

    original_handler = signal.signal(signal.SIGALRM, timeout_handler)

    try:
        signal.alarm(seconds)
        yield
    finally:
        signal.alarm(0)
        signal.signal(signal.SIGALRM, original_handler)

and used it as follows:

        with doTimeout(timeout):
            try:
                fcntl.flock(self.file, fcntl.LOCK_EX)
                self.locked = True
                return True
            except (OSError, IOError) as e:
                if e.errno == errno.EINTR:
                    return False
                raise

This all worked perfectly, but unfortunately I can only do this from the main thread because only the main thread can catch signals. Is there a way to do it from another thread?

My alternatives at this point are to periodically test the lock and then sleep, or launch a subprocess. Neither of these is ideal; is there a better way?

Edward Falk
  • 9,991
  • 11
  • 77
  • 112
  • 1
    Why [reinvent the wheel](https://py-filelock.readthedocs.io/en/latest/)? – dskrypa Jan 13 '23 at 22:14
  • This particular wheel only works on the main thread. I'm hoping to set a timeout in another thread. – Edward Falk Jan 15 '23 at 02:24
  • 1
    The filelock library that I linked to implements a timeout that works in threads. The implication of the question was meant to be, why write your own implementation when this one already exists that does exactly what you want. – dskrypa Jan 15 '23 at 02:42
  • Ooops, didn't realize you'd made a link. Let me follow it. – Edward Falk Jan 16 '23 at 01:06
  • OK, found the source code at https://github.com/tox-dev/py-filelock. It uses a polling/sleep loop, which is what I was doing. I guess that's the best approach then. – Edward Falk Jan 16 '23 at 01:43
  • @dskrypa make your comment an answer and I'll mark it as the solution. – Edward Falk Jan 26 '23 at 00:49

1 Answers1

0

You can use the filelock library to accomplish exactly what you are looking for. It supports a timeout argument to handle specifying a timeout before giving up on acquiring the lock.

Additionally, it handles cross-process locking in an OS-independent manner, using the with lock: syntax that should be familiar from stdlib multithreading / multiprocessing locks.

On Linux systems, it uses fcntl.flock().

dskrypa
  • 1,004
  • 2
  • 5
  • 17