【问题标题】:Multi-threaded fork()多线程 fork()
【发布时间】:2021-06-12 01:18:10
【问题描述】:

在多线程应用程序中,如果一个线程调用 fork(),它将只复制该线程的状态。所以创建的子进程将是一个单线程进程。如果某个其他线程持有调用 fork() 的线程所需的锁,则该锁将永远不会在子进程中释放。这是个问题。 为了解决这个问题,我们可以通过两种方式修改 fork()。要么我们可以复制所有线程,而不是只复制一个。或者我们可以确保(其他)非复制线程持有的任何锁都将被释放。那么在这两种情况下,修改后的 fork() 系统调用是什么。这两个哪个更好,或者哪个选项的优点和缺点是什么?

【问题讨论】:

  • 不要。 pthreads 工作组把自己逼到了一个角落,挖了一个逃生口,把他们糟糕的设计 () 的所有固有复杂性作为要求强加给用户。即使是像system() 这样的无害电话也会被此网络捕获。 () 设计,因为除了标准化作为共同元素的协议之外,ieee-pthreads 小组还着手设计全新的东西,并在其上加盖标准。只有在接缝处不太用力时才有效;是的,我是工作组的一员。

标签: multithreading operating-system locking fork


【解决方案1】:

这是一个棘手的问题。

POSIX 有pthread_atfork() 来解决混合分叉和线程创建的混乱局面。该手册页的 NOTES 部分讨论了互斥锁等。但是,它承认正确处理它很困难。

该函数与其说是fork() 的替代品,不如说是一种向pthread 库解释您的程序需要如何准备以使用fork() 的方式。

一般来说,不要尝试从 fork 的子线程启动线程,而是退出该子线程或尽快调用 exec,这样可以最大限度地减少问题。

这个帖子有一个good discussion of pthread_atfork()

【讨论】:

  • 您能解释一下或指出我的 pthread_atfork() 代码吗?它的代码与 fork() 有何不同?那里添加了哪些额外的东西?谢谢。
  • 我在回答中添加了更多信息。包括指向另一个包含一些代码的帖子的链接。
【解决方案2】:

...或者我们可以确保(其他)非复制线程持有的任何锁都将被释放。

这将比您意识到的要难,因为程序可以完全在用户模式代码中实现“锁”,在这种情况下,操作系统将不知道它们。

即使您小心地只使用操作系统已知的锁,您仍然会遇到一个更普遍的问题:仅使用一个线程创建一个新进程实际上与创建一个具有所有线程的新进程,然后立即杀死除其中一个之外的所有线程。

了解我们为什么不杀死线程。简而言之:锁不是唯一需要清理的状态。在 fork 调用的那一刻,任何存在于父级中但不存在于子级中的线程都可能正在制造需要清理的混乱。如果子线程中不存在该线程,那么您就失去了需要清理的知识。


我们可以复制所有线程,而不是只复制一个...

这也是一个潜在的问题。调用fork() 的一个线程会知道何时以及为什么调用fork(),并且它会准备 fork 调用。其他线程都不会有任何警告。而且,如果这些线程中的任何一个正在与进程外部 交互(例如,与远程服务通信),那么,在您之前有一个客户端与服务通信的地方,您突然有 两个客户,与同一个服务交谈,他们都认为他们是唯一的一个。这不会有好的结局。


不要从多线程程序调用fork()

在我参与的一个项目中:我们有一个大型多线程程序,需要生成其他进程。我们是如何做到的,我们让它在创建任何新线程之前生成一个简单的单线程“帮助”程序。然后,每当它需要生成另一个进程时,它就会向助手发送一条消息,助手就会这样做。

【讨论】:

    猜你喜欢
    • 2010-11-17
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多