如何在fork-exec上处理共享内存和共享信号量?

时间:2012-11-06 19:28:40

标签: c multithreading exec fork shared

我想为一个成熟的应用程序添加新功能,以便使用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生成新进程时,处理共享内存和共享信号量的正确方法是什么?

3 个答案:

答案 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);
    }

这让我关闭了十几个文件描述符。