35.9. fcntl —— 系统调用 fcntlioctl


    本模块的所有函数都接受文件描述符 fd 作为第一个参数。可以是一个整数形式的文件描述符,比如 sys.stdin.fileno() 的返回结果,或为 对象,比如 sys.stdin 提供一个 fileno(),可返回一个真正的文件描述符。

    在 3.3 版更改: 本模块的操作以前触发的是 ,现在则会触发 OSError

    这个模块定义了以下函数:

    fcntl.fcntl(fd, cmd, arg=0)

    对文件描述符 fd 执行 cmd 操作(能够提供 方法的文件对象也可以接受)。 cmd 可用的值与操作系统有关,在 fcntl 模块中可作为常量使用,名称与相关 C 语言头文件中的一样。参数 arg 可以是整数或 对象。若为整数值,则本函数的返回值是 C 语言 fcntl() 调用的整数返回值。若为字节串,则其代表一个二进制结构,比如由 struct.pack() 创建的数据。该二进制数据将被复制到一个缓冲区,缓冲区地址传给 C 调用 fcntl()。调用成功后的返回值位于缓冲区内,转换为一个 对象。返回的对象长度将与 arg 参数的长度相同。上限为 1024 字节。如果操作系统在缓冲区中返回的信息大于 1024 字节,很可能导致内存段冲突,或更为不易察觉的数据错误。

    如果 fcntl() 调用失败,会触发 OSError

    (fd, request, arg=0, mutate_flag=True)

    本函数与 函数相同,只是参数的处理更加复杂。

    request 参数的上限是 32位。termios 模块中包含了可用作 request 参数其他常量,名称与相关 C 头文件中定义的相同。

    参数 arg 可为整数、支持只读缓冲区接口的对象(如 )或支持读写缓冲区接口的对象(如 bytearray )。

    除了最后一种情况,其他情况下的行为都与 函数一样。

    如果为 False,缓冲区的可变性将被忽略,行为与只读缓冲区一样,只是没有了上述 1024 字节的上限——只要传入的缓冲区能容纳操作系统放入的数据即可。

    如果 mutate_flag 为 True(默认值),那么缓冲区(实际上)会传给底层的 系统调用 ioctl() ,其返回代码则会回传给调用它的 Python,而缓冲区的新数据则反映了 的运行结果。这里做了一点简化,因为若是给出的缓冲区少于 1024 字节,首先会被复制到一个 1024 字节长的静态缓冲区再传给 ioctl() ,然后把结果复制回给出的缓冲区去。

    如果 ioctl() 调用失败,则会触发 异常。

    举个例子:

    fcntl.flock(fd, operation)

    在文件描述符 fd 上执行加锁操作 operation (也接受能提供 fileno() 方法的文件对象)。 详见 Unix 手册 flock(2)。 (在某些系统中,此函数是用 fcntl() 模拟出来的。)

    如果 flock() 调用失败,就会触发 异常。

    fcntl.lockf(fd, cmd, len=0, start=0, whence=0)

    This is essentially a wrapper around the fcntl() locking calls. fd is the file descriptor of the file to lock or unlock, and cmd is one of the following values:

    • LOCK_UN ——解锁

    • LOCK_SH —— 获取一个共享锁

    如果 cmdLOCK_SHLOCK_EX,则还可以与 LOCK_NB 进行按位或运算,以避免在获取锁时出现阻塞。 如果用了 ,无法获取锁时将触发 ,此异常的 errno 属性将被设为 EACCESEAGAIN (视操作系统而定;为了保证可移植性,请检查这两个值)。 至少在某些系统上,只有当文件描述符指向需要写入而打开的文件时,才可以使用 LOCK_EX

    len 是要锁定的字节数,start 是自 whence 开始锁定的字节偏移量,whenceio.IOBase.seek() 的定义一样。

    • 1 —— 自缓冲区当前位置( )

    • 2—— 自文件末尾(os.SEEK_END)

    start 的默认值为 0,表示从文件起始位置开始。len 的默认值是 0,表示加锁至文件末尾。 whence 的默认值也是 0。

    示例(都是运行于符合 SVR4 的系统):

    1. import struct, fcntl, os
    2. f = open(...)
    3. rv = fcntl.fcntl(f, fcntl.F_SETFL, os.O_NDELAY)
    4. rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockdata)

    注意,在第一个例子中,返回值变量 rv 将存有整数;在第二个例子中,该变量中将存有一个 对象。lockdata 变量的结构布局视系统而定——因此可能采用 flock() 调用会更好。

    参见

    模块

    如果 os 模块中存在加锁标志 和 O_EXLOCK (仅在BSD上),那么 函数提供了 lockf() 和 函数的替代方案。