我想为一个成熟的应用程序添加新功能,以便使用fork(2)和exec(3)(目前为execl)开始执行另一个应用程序。
不幸的是,应用程序使用共享内存,共享信号量,并且有大量的打开文件描述符,这些描述符在调用fork时都是重复的。我知道我应该在子进程中调用execl之前关闭所有文件描述符,共享资源等,但是其中一部分是由第三方库处理的,我无法访问它们。
最重要的是所有应用程序都是线程化的(使用posix线程),但只要在子进程中fork和exec之间没有异步系统调用(根据http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them),这应该没问题。 / p>
我现在面临的问题是,execl调用似乎以某种方式破坏了共享资源,导致使用它们的线程出现死锁。这似乎只有在调用execl作为fork后立即退出子进程时才会发生,而_exit(2)不会产生这种行为。
使用fork和exec生成新进程时,处理共享内存和共享信号量的正确方法是什么?
答案 0 :(得分:1)
这里可能存在多个问题,包括fork()和exec()代码中的错误,甚至是程序使用共享内存和信号量的方式中的错误。
处理此问题的一种可能方法是使用system()函数。
这将在shell环境中运行命令并阻塞,直到程序退出。您可以生成一个新线程,然后调用系统。让内置函数处理正确的fork()和exec()。
如果您仍有问题,那么我会说您的共享内存/信号量与fork和exec不兼容。
答案 1 :(得分:1)
很可能是因为没有关闭孩子的文件描述符而导致死锁。 在尝试任何其他事情之前试试这个:
遍历子/proc/[pid]/fd
中的所有文件描述符并在调用exec
之前将其关闭。
如果这不是必须的话,那么你必须用MADV_DONTFORK
将所有内存(除了你的堆栈框架)标记为madvise
。您可以通过将映射范围与本地线程堆栈上的任何指针进行比较,从/proc/[pid]/maps
和本地堆栈帧中获取所有当前映射的列表。
答案 2 :(得分:1)
这里再次使用我正在使用的代码来关闭所有文件描述符(在注释中看起来不太好)。
DIR* hdir = opendir("/proc/self/fd/");
struct dirent* entry;
int fd;
if (hdir != NULL) {
while ((entry = readdir(hdir)) != NULL) {
fd = strtol(entry->d_name, NULL, 10);
if (fd > 2)
close(fd);
}
closedir(hdir);
}
这让我关闭了十几个文件描述符。