Как я могу сделать неблокирующий запрос на эксклюзивную блокировку с помощью файла#flock?

как я должен запросить неблокирующий замок?

почему Руби не файл#flock работать, как ожидалось, когда предпринимаются отдельные попытки заблокировать файл? Блокировка файла в блоке не является правильным решением для этой проблемы, потому что дело в том, чтобы показать поведение блокировки на постоянные замки. Использование файла#flock внутри блока освобождает блокировку при выходе блока, поэтому он не демонстрирует проблему должным образом.

файл#flock сбой различными способами, особенно при запросе блокировки Без блокировки. Ниже приводятся некоторые примеры.

неудачные примеры с файлом#flock

  • бесконечное ожидание при использовании нескольких эксклюзивных блокировок, так как #flock не предоставляет способ тайм-аута запроса блокировки.

    # First lock succeeds.
    f1 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f1.flock(File::LOCK_EX)
    # => 0
    
    # This never returns.
    f2 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f2.flock(File::LOCK_EX)
    
  • запрос неблокирующей блокировки при исключительной блокировке файла приводит к недопустимому аргументу исключение.

    f1 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f1.flock(File::LOCK_EX)
    # => 0
    
    f2 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f2.flock(File::LOCK_NB)
    # => Errno::EINVAL: Invalid argument - foo
    
  • в документации говорится, что #flock " блокирует или разблокирует файл в соответствии с locking_constant (логическим или значений в таблице ниже)."Однако, логичный или поднимает Errno::EINVAL или Errno::EBADF в зависимости от платформы.

    f1 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f1.flock(File::LOCK_EX)
    # => 0
    
    f2 = File.open('foo', File::RDWR|File::CREAT, 0644)
    f2.flock(File::LOCK_NB || File::LOCK_EX)
    # => Errno::EINVAL: Invalid argument - foo
    

родной файл#flock решение предпочтительнее

в то время как можно использовать модуль ожидания поднять Timeout::Error когда не удается получить монопольную блокировку, кажется как файл#flock должен быть в состоянии решить эту проблему изначально. Итак, как на самом деле можно запросить эксклюзивный замок без блокировки?

1 ответов


используйте модуль тайм-аута с эксклюзивными замками

можно использовать модуль ожидания чтобы установить продолжительность для #flock, чтобы получить эксклюзивную блокировку. Следующий пример поднимет Timeout::Error: execution expired, который затем может быть спасен любым способом, который кажется подходящим для приложения. Возвращение Нил когда таймер истекает, позволяет проверить выражение #flock на истинность.

require 'timeout'

f1 = File.open('foo', File::RDWR|File::CREAT, 0644)
f1.flock(File::LOCK_EX)
# => 0

f2 = File.open('foo', File::RDWR|File::CREAT, 0644)
Timeout::timeout(0.001) { f2.flock(File::LOCK_EX) } rescue nil
# => nil

используйте побитовое или для не-преграждая замка Попытки

документация файл#flock говорит:

блокирует или разблокирует файл в соответствии с locking_constant (логическое или значений в таблице ниже). Возвращает false, если указан параметр File:: LOCK_NB и операция в противном случае была бы заблокирована.

однако метод фактически ожидает побитовое или оператор, а не логическое или ключевое слово как определена в обработку.y по tOROP токен парсера. В результате правильный аргумент, позволяющий #flock возвращать false когда эксклюзивный замок терпит неудачу на самом деле File::LOCK_NB|File::LOCK_EX. Например:

f1 = File.open('foo', File::RDWR|File::CREAT, 0644)
f1.flock(File::LOCK_EX|File::LOCK_NB)
# => 0

f2 = File.open('foo', File::RDWR|File::CREAT, 0644)
f2.flock(File::LOCK_NB|File::LOCK_EX)
# => false

f1.close; f2.close
# => nil

это будет последовательно генерировать эксклюзивную блокировку, когда она доступна; в противном случае она немедленно возвращает ложное значение без накладных расходов на создание или спасение исключений. Очевидно, что модуль предназначен для использования именно таким образом, но в документации могут быть использованы некоторые разъяснения и дополнительные примеры легкий для понимания.