【发布时间】:2011-09-28 07:21:51
【问题描述】:
我正在尝试检查多线程应用程序。对于单线程应用程序,将进程分叉作为检查点是一种有效的技术。但是,没有多线程叉这样的东西。知道如何实现自己的多线程分支吗?对此类工作的任何参考将不胜感激。
【问题讨论】:
-
你又来了。正如我们在其他问题中讨论的那样,请接受一些答案。
标签: c linux multithreading fork
我正在尝试检查多线程应用程序。对于单线程应用程序,将进程分叉作为检查点是一种有效的技术。但是,没有多线程叉这样的东西。知道如何实现自己的多线程分支吗?对此类工作的任何参考将不胜感激。
【问题讨论】:
标签: c linux multithreading fork
没有可移植的方式来实现fork 的变体,它使用POSIX 提供的接口保留所有线程。在某些系统(例如 Linux)上,您可以实现一个高度不可移植、高度脆弱的版本:
使用ptrace跟踪所有线程(停止它们),然后在子进程中创建新的内核线程来复制父进程中的每个线程,并为其分配原始堆栈地址、指令指针、寄存器值,等等。您还需要修补线程描述符以了解它们的新内核空间线程 ID,如果线程正在查询其线程 ID,则需要避免其中的竞争条件。
使用vfork 后跟SIGSTOP 来停止父进程,让自己有机会重新创建它的线程状态,而不会改变你的状态。这似乎是可能的,但足够困难,我想我会在尝试详细说明时感到头疼......
(新添加)在分叉之前捕获信号处理程序中的每个线程,并将ucontext_t 参数保存到信号处理程序。然后分叉并创建新的内核线程(使用clone),让它们自己发出信号,然后覆盖ucontext_t,信号处理程序让信号处理程序返回到您尝试复制的原始线程的上下文中。当然,这都需要非常巧妙的同步……
或者,您可以寻找一种基于内核的“进程休眠”方法来进行检查点,这种方法不会那么骇人听闻...
【讨论】:
pthread_atfork 用于不同的目的,由于设计它的人的推理错误,它实际上在很大程度上是无用的。 (这个想法是让 prefork 函数获取所有全局锁,并让父/子 postfork 函数全部释放它们,但是尝试释放任何锁的子进程将给出错误或调用未定义的行为,因为子进程中的新线程不是任何锁的所有者。)
“多线程分叉”是什么意思?一个复制多线程进程的函数,以便分叉的进程拥有与旧进程一样多的线程?一个创建一个复制旧线程状态的新线程的函数?
后者是不可能的,因为地址空间是共享的。当前线程状态的副本将使用当前线程的堆栈,新线程和旧线程将争夺堆栈。
另见:
【讨论】:
fork 只是在新进程中复制调用线程。没有办法在新进程中保留调用进程的所有线程。如果您打算在子进程中执行除exec 或_exit 之外的任何操作,那么混合线程和fork 是一个非常非常糟糕的主意。