Python fcntl не блокируется, как ожидалось - программирование
Подтвердить что ты не робот

Python fcntl не блокируется, как ожидалось

В ОС на основе Debian (Ubuntu, Debian Squeeze) я использую fttnt(), чтобы заблокировать файл. Как я понимаю из того, что я читал, fnctl.flock блокирует файл таким образом, что будет вызываться исключение, если другой клиент хочет заблокировать один и тот же файл.

Я построил небольшой пример, который я бы ожидал, чтобы выбросить excepiton, поскольку я сначала заблокировал файл, а затем, сразу после этого, я снова попытаюсь заблокировать его:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import fcntl
fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX)
try:
    fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    print("can't immediately write-lock the file ($!), blocking ...")
else:
    print("No error")

Но пример просто печатает "Без ошибок".

Если я разорву этот код до двух клиентов, работающих одновременно (одна блокировка, а затем ожидание, другая попытка блокировки после первой блокировки уже активна), я получаю такое же поведение - никакого эффекта вообще.

Какое объяснение этого поведения?

ИЗМЕНИТЬ

Изменяется по требованию ночного скребка, эта версия также выводит "Нет ошибки", хотя я не ожидал бы этого:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import fcntl
import time
fcntl.flock(open('/tmp/locktest', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
try:
    fcntl.flock(open('/tmp/locktest', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    print("can't immediately write-lock the file ($!), blocking ...")
else:
    print("No error")
4b9b3361

Ответ 1

Получил это. Ошибка в моем script заключается в том, что я создаю новый дескриптор файла для каждого вызова:

fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX | fcntl.LOCK_NB)
(...)
fcntl.flock(open('/tmp/locktest', 'r'), fcntl.LOCK_EX | fcntl.LOCK_NB)

Вместо этого я должен назначить объект файла переменной и попытаться заблокировать:

f = open('/tmp/locktest', 'r')
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
(...)
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)

Чем я получаю исключение, которое я хотел увидеть: IOError: [Errno 11] Resource temporarily unavailable. Теперь я должен думать о том, в каких случаях имеет смысл использовать fcntl.

Ответ 2

Старый пост, но если кто-нибудь еще найдет его, я получаю следующее:

>>> fcntl.flock(open('test.flock', 'w'), fcntl.LOCK_EX)
>>> fcntl.flock(open('test.flock', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
# That didn't throw an exception

>>> f = open('test.flock', 'w')
>>> fcntl.flock(f, fcntl.LOCK_EX)
>>> fcntl.flock(open('test.flock', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 35] Resource temporarily unavailable
>>> f.close()
>>> fcntl.flock(open('test.flock', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)
# No exception

Похоже, что в первом случае файл закрывается после первой строки, по-видимому, потому, что файл-объект недоступен. Закрытие файла освобождает блокировку.

Ответ 3

У меня была та же проблема... Я решил, что он держит открытый файл в отдельной переменной:

Не работает:

fcntl.lockf(open('/tmp/locktest', 'w'), fcntl.LOCK_EX | fcntl.LOCK_NB)

Работает:

lockfile = open('/tmp/locktest', 'w')
fcntl.lockf(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)

Я думаю, что первый не работает, потому что открытый файл собранный мусор, закрыт и заблокирован.

Ответ 4

Есть два улова. В соответствии с документацией:

  • Когда операция LOCK_SH или LOCK_EX, она также может быть побитовой ORed с помощью LOCK_NB, чтобы избежать блокировки при сборе блокировки. Если используется LOCK_NB, и блокировка не может быть получена, будет добавлен IOError, и исключение будет иметь атрибут errno, установленный на EACCES или EAGAIN (в зависимости от операционной системы, для переносимости, проверьте для обоих значений).

    Вы забыли установить LOCK_NB.

  • По крайней мере в некоторых системах LOCK_EX может использоваться, только если дескриптор файла ссылается на файл, открытый для записи.

    У вас есть файл, открытый для чтения, который может не поддерживать LOCK_EX в вашей системе.

Ответ 5

Вам нужно передать файловый дескриптор (доступный путем вызова метода fileno() объекта файла). Ниже приведен код IOError, когда один и тот же код запускается в отдельном интерпретаторе.

>>> import fcntl
>>> thefile = open('/tmp/testfile')
>>> fd = thefile.fileno()
>>> fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)

Ответ 6

Try:

global f
f = open('/tmp/locktest', 'r')

Когда файл закрыт, замок будет исчезать.