Блокировка файлов с помощью Fcntl: сбивающая с толку ошибка, связанная с использованием и потребностью - PullRequest
2 голосов
/ 04 июля 2010

Следующий скрипт Perl выводит «УСПЕХ», как и следовало ожидать:

use Fcntl qw(:DEFAULT :flock);
sysopen(LF, "test.txt", O_RDONLY | O_CREAT) or die "SYSOPEN FAIL: $!";
if(flock(LF, LOCK_EX)) { print "SUCCESS.\n"; }
else { print "FAIL: $!\n"; }

Но теперь замените эту первую строку на

require "testlib.pl";

, где testlib.pl содержит

use Fcntl qw(:DEFAULT :flock);

1;

Теперь, как ни странно, скрипт завершается неудачно, например:

FAIL: Bad file descriptor

Вопрос: почему?

ДОБАВЛЕНО:

А теперьЯ знаю почему - спасибо!- Мне интересно, как лучше всего справиться с этим:

  1. Просто сделайте use Fcntl дважды, один раз в основном сценарии и один раз в необходимой библиотеке (как основного сценария, так иэто нужно библиотеке).
  2. Заменить O_RDONLY на & O_RDONLY и т. д.
  3. Заменить O_RDONLY на O_RDONLY () и т. д.
  4. Что-то еще?

Ответы [ 3 ]

3 голосов
/ 04 июля 2010

Вышеупомянутым use вы лишаете Perl-анализатор знаний, которые O_RDONLY et al. подпрограммы без параметров. Вы должны быть немного более многословным в этой ситуации:

sysopen(LF, "test.txt", O_RDONLY() | O_CREAT()) or die "SYSOPEN FAIL: $!";
if(flock(LF, LOCK_EX())) { print "SUCCESS.\n"; }

РЕДАКТИРОВАТЬ: Чтобы уточнить, без скобок, O_RDONLY и O_CREAT интерпретировались как голые слова (строки), которые ведут себя не так, как вы ожидаете, когда двоичные или объединены:

$ perl -le 'print O_RDONLY | O_CREAT'
O_SVOO\Y

(Отдельные символы поразрядны или объединены).

В этом случае строка «O_SVOO \ Y» (или что-то еще в вашей системе) интерпретировалась как число от 0 до sysopen, что, следовательно, будет работать до тех пор, пока O_RDONLY равно 0 (как это типично) и файл уже существовал (поэтому O_CREAT был лишним). Но fcntl явно не так простителен с нечисловыми аргументами:

$ perl -e 'flock STDOUT, "LOCK_EX" or die "Failed: $!"'
Failed: Bad file descriptor at -e line 1.

Аналогично:

$ perl -e 'flock STDOUT, LOCK_EX or die "Failed: $!"'
Failed: Bad file descriptor at -e line 1.

Тем не менее:

$ perl -e 'use Fcntl qw(:flock); flock STDOUT, LOCK_EX or die "Failed: $!"'
(no output)

Наконец, обратите внимание, что use strict предоставляет много полезных подсказок.

2 голосов
/ 04 июля 2010

Строка use Fcntl qw(:DEFAULT :flock); не только загружает библиотеку Fcntl для вас, но и экспортирует некоторые символы в пространство имен вашего скрипта.Если вы переместите это в другую область, то константы O_RDONLY, O_CREAT, LF и LOCK_EX больше не будут доступны для вас, и ваш код не будет делать то же самое [однако вы все равно можете достичь их, если вызнать, в каком пространстве имен они оказались - поскольку это был сценарий, который выполнял экспорт, вы можете вызвать & main :: NAME или просто & NAME, но тогда вы должны знать, что другой файл делает со своим кодом, а это не так.очень чистый] .

Это описано в документации под ЭКСПОРТНЫЕ СИМВОЛЫ :

По умолчанию в вашей системе используются константы F_ * и O_ * (например,, F_DUPFD и O_CREAT) и константа FD_CLOEXEC экспортируются в ваше пространство имен.

Вы можете запросить предоставление констант flock () (LOCK_SH, LOCK_EX, LOCK_NB и LOCK_UN) с помощью тега ": flock".См. Exporter.

Если вы добавите строки

use strict;
use warnings;

в начало вашего скрипта, вы получите более информативные сообщения об ошибках, такие как «Имя» main :: O_RDONLY »используется только один раз: возможный тип в строке ... ", что даст вам подсказку, что эти определения констант больше не видны.

Редактировать: в ответ на ваш вопрос, лучшая практика будет # 1,включить оператор использования в каждый файл, который нуждается в нем.См. perldoc -f use - библиотека Fcntl включается только один раз, но вызов import () выполняется каждый раз, когда это необходимо, что вам и нужно.

0 голосов
/ 04 июля 2010

использование эквивалентно:

BEGIN { require Module; Module->import( LIST ); }

, гарантирующему, что функции импорта доступны до начала выполнения кода.Когда вы заменяете use на require, он просто считывает код в лексической точке программы, где он существует.

...