C语言 避免共享对象中的内部线程



我们有一个产品,它加载一个共享对象,该对象使用"dll 注入"和"检测"技术监视随机进程(我们称之为 myDb)内部函数调用。

目前,我们的共享对象有一个内部线程,该线程从我们的主进程(外部实体)接收()消息。

在myDb fork()s之前,一切都运行良好,并创建了一个相同的子进程,该子进程不会以execve()结束。这个相同的子进程主线程在调用 fork() 的父线程的上下文中启动,所有其他父线程的线程都不再存在于子线程中。这可能会破坏我们的共享对象内部状态,因为我们的内部线程可以在任何执行点消失(请参阅有关在 http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them 中混合线程和分支的更多信息)。

MyDb 可以在不问我们的情况下使用分叉,因此,如果我错了,请纠正我,似乎我们别无选择,只能让我们的代码在没有内部线程的情况下工作。

我能想到的唯一选择是异步 I/O。 根据 http://man7.org/linux/man-pages/man7/aio.7.html,来自异步例程的通知是使用 sigevent 完成的。sigEvent 可以使用 SIGEV_SIGNAL 来接收通过信号接收通知,或者通过使用SIGEV_THREAD根据手册页,该信号在下面使用实际线程。 因此,在我看来,我们唯一的选择是将异步 I/O 与 SIGEV_SIGNAL 选项一起使用。但这也有很多限制,因为处理信号处理程序中的消息是危险的,因为只能调用异步信号安全函数。

我很乐意在这里对我的问题提出任何建议。

谢谢。

我发现的最佳解决方案是使用pthread_atfork()注册处理程序。 此 API 可帮助将fork()与驻留在进程中的其他线程同步,以避免内存不一致。

更多 https://linux.die.net/man/3/pthread_atfork

不幸的是,使用pthread_atfork()解决这个问题并不总是那么容易,因为每个进程的线程都必须合作,这是一个严格的假设。除此之外,它还打破了我们的设计。

我们决定改度,使用工作而不是线程。我将解释:

通常,在创建线程时,它们大部分时间都会阻塞某些调用(read()sleep()等),在这些情况下,线程性并不是真正需要的,使用作业可能更有意义。

我们开发了一个 JobScheduler() 类,它将作业调度到注册到它的作业(按超时、fd 就绪读取等)。 现在,在本课程中,我们定义了一个分叉安全区,这是我们唯一允许分叉发生的区域,如果在正在进行的作业期间发生分叉,分叉将被延迟到作业结束。 这导致了一个限制,即作业执行必须相对较快,并且绝不会阻塞线程。

这个 fork-safe 区域使我们能够在子进程中强制执行内存空间的一致性(使用pthread_atfork()),此外,我们还可以在 child-post-fork 回调中重新创建这个工作线程,这将使 fork 限制不可见。

最新更新