pthread_atfork 锁定习惯用法坏了?

R..*_*R.. 6 c posix fork pthreads

标准用法pthread_atfork应该是在 pre-fork 处理程序中获取所有锁,并在父处理程序和子处理程序中释放它们。然而,据我所知,这是不可能的。pthread_mutex_unlock如果调用线程不是互斥锁的所有者,则指定为具有未定义的行为(在正常或默认类型互斥锁的情况下)或失败(在递归或错误检查互斥锁的情况下)。并且在注册的子处理程序中pthread_atfork,调用线程是新创建进程的主线程,因此不能是互斥锁的所有者。

是我弄错了还是整个pthread_atfork习语被设计破坏了并且基本上无法使用?

编辑:我也没有看到针对该问题的任何有效(便携式)解决方法。理想情况下,可以在子进程中销毁并重新初始化互斥锁,除了调用pthread_mutex_destroy已初始化的互斥锁被指定为未定义行为,以适应其中互斥锁不是 POD 但涉及对某些内核级对象的引用的荒谬实现。

小智 1

我认为这是来自 man 的相关文本:

当调用 fork() 时,只有 调用线程会在子进程中复制。同步变量在子级中保持与调用 fork() 时在父级中相同的状态。因此,例如,互斥锁可能由子进程中不再存在的线程持有,并且任何关联的状态可能不一致。父进程可以通过显式代码通过 pthread_atfork() 获取和释放对子进程至关重要的锁来避免这种情况。此外,任何关键线程都需要在子级中重新创建并重新初始化为正确的状态(也通过 pthread_atfork())。

在子进程中执行 atfork 处理程序的线程是在父进程中执行 atfork 准备处理程序的线程的精确副本,因此有权解锁互斥体。

  • 刚刚使用 glibc 进行了测试,子级中的解锁在默认互斥体类型下成功,但在错误检查或递归互斥体下失败。据我所知,这符合规范,它对默认类型没有要求,但要求其他类型在调用者不是所有者时以“EPERM”失败。 (3认同)