У Windows есть возможность открыть файл с эксклюзивными правами доступа. Unix этого не делает.
Чтобы обеспечить эксклюзивный доступ к некоторому файлу или устройству, в Unix обычно используется файл блокировки, обычно хранящийся в каталоге /var/lock.
Инструкция C open( "/var/lock/myLock.lock", O_RDWR | O_CREAT | O_EXCL, 0666 )
возвращает -1, если файл блокировки уже существует, иначе он его создает. Функция является атомарной и обеспечивает отсутствие состояния гонки.
Когда ресурс освобождается, файл блокировки удаляется следующей инструкцией
remove( "/var/lock/myLock.lock" )
.
Есть две проблемы с этим методом.
-
Программа может завершиться без удаления блокировки. Например, потому что он убит, сбой или что-то еще. Файл блокировки остается на месте и будет препятствовать любому доступу к ресурсу, даже если он больше не используется.
-
Файл блокировки создается с правами на запись в группе и мире, но обычно принято настраивать учетные записи для использования маски разрешения, которая очистит разрешение на запись в группе и мире. Таким образом, если бы у нас был надежный метод определения того, что блокировка является сиротой (не используется), пользователю, не являющемуся владельцем файла, не удастся его удалить.
Для записи я использую файл блокировки для обеспечения эксклюзивного доступа к устройству, подключенному к последовательному порту (фактически/dev/ttyUSBx). Консультативный метод, требующий сотрудничества, в порядке. Но эксклюзивный доступ должен быть обеспечен между разными пользователями.
Есть ли лучший способ синхронизации, чем файл блокировки? Как определить, работает ли процесс, создавший файл блокировки? Как сделать возможным, чтобы другой пользователь удалил файл блокировки, если он не используется?
Одно из решений, которое я придумал, заключалось в том, чтобы использовать файл как файл сокета Unix. Если файл существует, попробуйте подключиться с помощью файла. Если это не удается, мы можем предположить, что процесс владельца файла мертв. Для этого требуется, чтобы в процессе владельца был запущен цикл сокета accept()
. К сожалению, система больше не будет атомной.