Как я могу сделать неблокирующий запрос на эксклюзивную блокировку с помощью файла#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
это будет последовательно генерировать эксклюзивную блокировку, когда она доступна; в противном случае она немедленно возвращает ложное значение без накладных расходов на создание или спасение исключений. Очевидно, что модуль предназначен для использования именно таким образом, но в документации могут быть использованы некоторые разъяснения и дополнительные примеры легкий для понимания.