You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何给线程中的系统调用添加超时?以fcntl.flock为例

问题

希望调用fcntl.flock()给文件加锁并设置超时。参考《Timeout on a function call》中的方案,用contextmanager封装了通过Unix信号实现超时的代码:

@contextmanager
def doTimeout(seconds):
    """Creates a "with" context that times out after the
    specified time."""
    def timeout_handler(signum, frame):
        pass

    original_handler = signal.signal(signal.SIGALRM, timeout_handler)

    try:
        signal.alarm(seconds)
        yield
    finally:
        signal.alarm(0)
        signal.signal(signal.SIGALRM, original_handler)

使用方式如下:

with doTimeout(timeout):
    try:
        fcntl.flock(self.file, fcntl.LOCK_EX)
        self.locked = True
        return True
    except (OSError, IOError) as e:
        if e.errno == errno.EINTR:
            return False
        raise

该方案在主线程中运行正常,但由于只有主线程能捕获信号,无法在其他线程中使用。是否有办法在子线程中实现?目前备选方案是轮询锁状态后休眠,或启动子进程,但均不理想,是否有更优方案?

解决方案

可以用非阻塞锁+select等待的方式实现,完全避开信号机制,子线程也能正常工作,比轮询更高效。

核心思路:

  • 先用fcntl.LOCK_EX | fcntl.LOCK_NB以非阻塞模式尝试加锁,成功则直接返回
  • 若加锁失败(返回EAGAIN/EWOULDBLOCK),用select.select()等待文件描述符变为可写(排他锁等待时,文件描述符会处于可写状态),同时设置超时时间

实现代码如下:

import fcntl
import select
import errno

def lock_with_timeout(file_obj, timeout):
    """给文件对象加排他锁,支持超时,可在子线程中使用"""
    try:
        # 非阻塞模式尝试加锁
        fcntl.flock(file_obj, fcntl.LOCK_EX | fcntl.LOCK_NB)
        file_obj.locked = True
        return True
    except (OSError, IOError) as e:
        if e.errno not in (errno.EAGAIN, errno.EWOULDBLOCK):
            # 非锁占用类错误,直接抛出
            raise
    
    # 等待文件可写,同时设置超时
    try:
        ready, _, _ = select.select([], [file_obj], [], timeout)
        if ready:
            # 文件可写时再次加锁
            fcntl.flock(file_obj, fcntl.LOCK_EX)
            file_obj.locked = True
            return True
        else:
            # 超时返回
            return False
    except (OSError, IOError) as e:
        if e.errno == errno.EINTR:
            # 被信号中断,视为超时
            return False
        raise

方案优势

  • 不依赖信号机制,子线程可正常使用
  • 基于select的等待是内核级别的,比轮询休眠更高效,无CPU资源浪费
  • 逻辑简洁,无需额外线程/进程开销

使用示例:

if lock_with_timeout(self.file, timeout):
    # 加锁成功后的业务逻辑
else:
    # 超时处理逻辑

内容的提问来源于stack exchange,提问作者Edward Falk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:05:22