- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我们有一个使用 ZeroC's Ice 的 C++ 共享库RPC 的库,除非我们关闭 Ice 的运行时,否则我们会观察到子进程卡在随机互斥体上。 Ice 运行时启动线程,有许多内部互斥体,并为服务器保持打开的文件描述符。
此外,我们有一些自己的互斥锁来保护我们的内部状态。
我们的共享库被数百个内部应用程序使用,因此我们无法控制进程何时调用 fork(),因此我们需要一种方法来安全地关闭 Ice 并在进程派生时锁定我们的互斥量。
在 pthread_atfork() 上阅读 POSIX 标准关于处理互斥锁和内部状态:
Alternatively, some libraries might have been able to supply just a child routine that reinitializes the mutexes in the library and all associated states to some known value (for example, what it was when the image was originally executed). This approach is not possible, though, because implementations are allowed to fail *_init() and *_destroy() calls for mutexes and locks if the mutex or lock is still locked. In this case, the child routine is not able to reinitialize the mutexes and locks.
在 Linux 上,this test C program从子 pthread_atfork() 处理程序中的 pthread_mutex_unlock() 返回 EPERM。 Linux 需要将 _NP 添加到 PTHREAD_MUTEX_ERRORCHECK 宏才能编译。
此程序链接自 good thread .
鉴于解锁或销毁子进程中的互斥量在技术上是不安全或不合法的,我认为最好有指向互斥量的指针,然后让子进程在堆上创建新的 pthread_mutex_t 并单独保留父进程的互斥量,从而有一个小的内存泄漏。
唯一的问题是如何重新初始化库的状态,我正在考虑重置 pthread_once_t。可能是因为 POSIX 有一个 pthread_once_t 的初始值设定项,它可以重置为初始状态。
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
static pthread_mutex_t *mutex_ptr = 0;
static void
setup_new_mutex()
{
mutex_ptr = malloc(sizeof(*mutex_ptr));
pthread_mutex_init(mutex_ptr, 0);
}
static void
prepare()
{
pthread_mutex_lock(mutex_ptr);
}
static void
parent()
{
pthread_mutex_unlock(mutex_ptr);
}
static void
child()
{
// Reset the once control.
pthread_once_t once = PTHREAD_ONCE_INIT;
memcpy(&once_control, &once, sizeof(once_control));
}
static void
init()
{
setup_new_mutex();
pthread_atfork(&prepare, &parent, &child);
}
int
my_library_call(int arg)
{
pthread_once(&once_control, &init);
pthread_mutex_lock(mutex_ptr);
// Do something here that requires the lock.
int result = 2*arg;
pthread_mutex_unlock(mutex_ptr);
return result;
}
在上面的 child() 示例中,我只通过复制一个用 PTHREAD_ONCE_INIT 初始化的新 pthread_once_t 来重置 pthread_once_t。只有在子进程中调用库函数时才会创建新的 pthread_mutex_t。
这很棘手,但也许是处理这种绕过标准的最佳方式。如果 pthread_once_t 包含互斥锁,那么系统必须有一种方法可以从 PTHREAD_ONCE_INIT 状态对其进行初始化。如果它包含一个指向堆上分配的互斥量的指针,那么它将被迫分配一个新的互斥量并在 pthread_once_t 中设置地址。我希望它不会将 pthread_once_t 的地址用于任何会打败它的特殊内容。
正在搜索 comp.programming.threads group for pthread_atfork()展示了很多很好的讨论,而 POSIX 标准真正提供的解决这个问题的能力是多么的少。
还有一个问题是,人们应该只从 pthread_atfork() 处理程序调用异步信号安全函数,并且出现了 most important one is the child handler。 ,其中只完成了一个 memcpy()。
这个有用吗?有没有更好的方法来处理我们共享库的需求?
最佳答案
恭喜,您发现了标准中的缺陷。 pthread_atfork
从根本上无法解决它为使用互斥体而创建的问题,因为不允许子进程中的处理程序对它们执行任何操作:
一个可能的解决方法是在这里使用 POSIX 信号量代替互斥量。信号量没有所有者,因此如果父进程锁定它 (sem_wait
),则父进程和子进程都可以解锁 (sem_post
) 各自的副本,而无需调用任何未定义的行为。
顺便说一句,sem_post
是异步信号安全的,因此 child 使用绝对合法。
关于c - 如何使用 pthread_atfork() 和 pthread_once() 重新初始化子进程中的互斥量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2620313/
pthread_atfork 用法的标准用法应该是获取预 fork 处理程序中的所有锁,并在父处理程序和子处理程序中释放它们。但是据我所知,这是不可能的。 pthread_mutex_unlock 如
某些库可能会使用 pthread_atfork() 注册一些处理程序。我不需要它们,因为我只将 fork() 与 exec() 一起使用。此外,它们在某些情况下可能会造成麻烦。那么,有没有办法重置已注
我正在实现一个库。我只能修改文件 mylib.c、mylib.h,而不能修改另一个文件中的 main()。 当 main() 中的进程调用 mylib_init() 时,便可以开始使用 mylib.h
我有一个旧应用程序,它使用 pthread 库中的 pthread_atfork 函数来注册子 Hook 。我正在将应用程序移动到使用 glibc 2.14.90 的较新构建环境。 pthread_a
我有一个监视器/(看门狗类线程)线程,用于查询所有线程的性能统计信息。来自/proc/self/tasks 的thread 的thread 查询列表 一旦创建了列表,我不想再读取/proc/self/
我们有一个使用 ZeroC's Ice 的 C++ 共享库RPC 的库,除非我们关闭 Ice 的运行时,否则我们会观察到子进程卡在随机互斥体上。 Ice 运行时启动线程,有许多内部互斥体,并为服务器保
我在我的项目中使用 libUV,但在链接时出现以下错误... In function `uv__signal_global_init': ... undefined reference to `pth
我是一名优秀的程序员,十分优秀!