代码之家  ›  专栏  ›  技术社区  ›  dreeves

使用fcntl锁定文件:涉及“使用”和“需要”的令人困惑的错误

  •  2
  • dreeves  · 技术社区  · 14 年前

    下面的Perl脚本按照您的期望输出“success”:

    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;o;rdonly等替换o rdonly。
    3. 将o摼rdonly替换为o摼rdonly()等。
    4. 还有别的吗?
    3 回复  |  直到 14 年前
        1
  •  2
  •   Ether    14 年前

    线 use Fcntl qw(:DEFAULT :flock); 不只是为您加载fcntl库,还将一些符号导出到脚本的命名空间中。如果您将其移动到另一个范围,那么常量o rdonly、o_creat、lf和lock_ex将不再对您可用,并且您的代码不会执行相同的操作。 [但是,您仍然可以访问它们,如果您知道它们最终位于哪个命名空间中--因为它是一个执行导出的脚本,您可以调用&main::name或简单地调用&name,但是您必须了解另一个文件对其代码所做的操作,这不是很干净] .

    这在下面的文档中进行了描述 EXPORTED SYMBOLS :

    默认情况下,系统的f_x和o_x常量(例如,f_dupfd和o_creat)和fd_cloexec常量将导出到您的命名空间中。

    您可以请求使用标记“:flock”提供flock()常量(lock_sh、lock_ex、lock_nb和lock_un)。见出口商。

    如果你加上线条

    use strict;
    use warnings;
    

    在脚本顶部,您将看到更多信息性错误消息,如“name”main::o rdonly“used only once:possible type at line…”,这将提示您这些常量定义不再可见。

    编辑:针对您的问题,最佳做法是1,包括 每个需要它的文件中的use语句。见 perldoc -f use --fcntl库只包含一次,但每次需要时都会调用import(),这正是您想要的。

        2
  •  3
  •   Sean    14 年前

    如上所述 use ,您剥夺了Perl解析器的知识 O_RDONLY 等。是无参数子程序。在这种情况下,你必须更详细一点:

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

    编辑:为了进一步阐述,没有括号, 俄罗斯方块 O_CREAT 被解释为空词(字符串),当二元或二元组合在一起时,它们的行为不符合您的预期:

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

    (单个字符正在按位或“组合在一起”)。

    在这种情况下,字符串“o_svoo \y”(或系统上的任何字符串)被解释为数字0到 sysopen 因此,只要 俄罗斯方块 是0(通常如此),文件已经存在(因此 奥克拉特 是多余的)。但是 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 提供了许多有用的线索。

        3
  •  0
  •   ennuikiller    14 年前

    使用相当于:

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

    确保导入函数在代码开始执行之前可用。当用require替换use时,它只是在程序中它所在的词法点读取中的代码。