我们有一个产品,它使用“dll注入”和“检测”技术加载一个共享对象,该对象监视随机进程(我们称之为mydb)中的内部函数调用。
目前,我们的共享对象有一个内部线程,该线程接收来自我们的主进程(外部实体)的消息。
直到mydb fork()创建了一个不以execve()结束的相同子进程,这一切都能正常工作。这个相同的子进程主线程在父线程称为Frk()的上下文中启动,并且所有其他父线程在子中不再存在。这可能会损坏我们的共享对象内部状态,因为我们的内部线程在执行的任何一点都会消失(参见更多关于在http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them中用叉混合线程)。
mydb可以不用问我们就使用fork,因此,如果我错了,请纠正我,似乎我们别无选择,只能让代码在没有内部线程的情况下工作。
我唯一能想到的是异步I/O。
根据http://man7.org/linux/man-pages/man7/aio.7.html,来自异步例程的通知是使用sigevent完成的。sigevent可以使用sigev_信号来接收使用信号的通知,或者使用sigev_线程,根据手册页,该线程使用下面的实际线程。
所以,在我看来,我们唯一的选择就是使用sigev_信号选项的异步i/o。但这也有很多限制,因为在信号处理程序中处理消息是危险的,因为只能调用异步信号安全函数。
对于我的问题,我很乐意在此提出任何建议。
谢谢。

最佳答案

我找到的最佳解决方案是使用pthread_atfork()注册处理程序。
这个api可以帮助将fork()与进程中的其他线程同步,以避免内存不一致。
https://linux.die.net/man/3/pthread_atfork
不幸的是,使用pthread_atfork()解决这个问题并不总是容易的,因为每个进程的线程都必须协作,这是一个严格的假设。除此之外,它还破坏了我们的设计。
我们决定改变态度,用工作代替工作。我会解释:
通常,在创建线程时,它们都会在某些调用(read()sleep(),等等)上阻塞大部分时间,在这些情况下,实际上并不需要线程性,使用作业可能更有意义。
我们开发了一个jobscheduler()类,它将作业分派给注册到它的那些作业(每次超时、fd read等等)。
现在,在这个类中,我们定义了一个fork安全区域,这是我们唯一允许fork发生的区域,如果fork发生在正在进行的作业中,那么fork将被延迟,直到作业结束。
这导致了一个限制,即作业执行必须相对较快,并且决不能阻塞线程。
此fork安全区域使我们能够强制子进程中的内存空间的一致性(使用pthread_atfork()),此外,我们还可以在子post fork回调中重新创建此工作线程,这将使fork限制不可见。

关于c - 避免共享对象中的内部线程,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49048559/

10-11 22:08
查看更多