我们有一个产品可以加载一个共享对象,该对象使用&#d; dll注入'来跟踪随机进程内的内部函数调用(让我们称之为myDb)。和'仪器仪表'技术。
目前,我们的共享对象有一个内部线程,它从我们的主进程recv()消息,这是一个外部实体。
这一切都运行良好,直到myDb fork()s并创建一个相同的子进程,它不会以execve()结束。这个相同的子进程主线程在调用fork()的父线程的上下文中开始,并且子进程中不再存在所有其他父进程的线程。这可能会破坏我们的共享对象内部状态,因为我们的内部线程可以在任何执行点消失(请参阅http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them中有关将线程与forks混合的更多内容。)
MyDb可以在不问我们的情况下使用叉子,所以,如果我错了,请纠正我,似乎我们别无选择,只能使我们的代码在没有内部线程的情况下工作。
我能想到的唯一选择是异步i / o。 根据{{3}},异步例程的通知使用sigevent完成。 sigevent可以使用SIGEV_SIGNAL来接收使用信号的通知或使用SIGEV_THREAD,根据手册页使用SIGEV_THREAD下面的实际线程。 因此,在我看来,我们唯一的选择是使用SIGEV_SIGNAL选项的异步i / o。但是这也存在许多限制,因为处理信号处理程序内的消息是危险的,因为只能调用异步信号安全函数。
我很高兴在这里对我的问题提出任何建议。
感谢。
答案 0 :(得分:0)
我找到的最佳解决方案是使用pthread_atfork()
注册处理程序。
此API可以帮助将fork()
与驻留在进程中的其他线程同步,以避免内存不一致。
https://linux.die.net/man/3/pthread_atfork
中的更多内容不幸的是,使用pthread_atfork()
并不总是很容易解决这个问题,因为每个过程都是如此。线程必须合作,这是一个严格的假设。除此之外,它还打破了我们的设计。
我们决定改变态度并使用职位代替线程。我将解释:
通常,在创建线程时,它们都会在一些调用(read()
,sleep()
等等)上阻塞大部分时间,在这些情况下,实际上并不需要线程,它可能更有意义的是使用工作。
我们开发了一个JobScheduler()类,它将作业调度到已注册的作业(Per timeout,fd ready read等)。 现在,在这个类中,我们定义了一个fork-safe-zone区域,它是我们允许fork发生的唯一区域,如果在正在进行的作业期间发生fork,则fork将被延迟直到作业结束。 这导致了一个限制,即作业执行必须相对较快,绝不会阻塞该线程。
这个fork-safe-zone使我们能够强制子进程中内存空间的一致性(使用pthread_atfork()
),此外,我们还可以在子进程中重新创建这个工作线程。 fork回调,这将使fork限制不可见。