调用" fork()execvp()_ exit()" ,这个过程没有退出

时间:2014-07-09 12:53:52

标签: c fork execvp

所以简短的总结是 - 我有一个程序,递归搜索具有特定扩展名的文件。每次找到一个,它都会复制,对副本进行一些更改,创建一个补丁(通过使用diff和execvp())并删除原始文件。

我遇到的问题是,在几百个文件之后,fork()返回“资源暂时不可用”。我添加了一个计数器,以查看发生此故障时仍有多少进程在运行,并且看起来没有关闭 - 打开的进程数始终与处理的文件数相同。

现在,我觉得流程应该是这样的 - fork(); //创建子进程 dostuff(); //在子进程中 _exit(1); //将控制权返回给父

但事情似乎并不那么简单。也许这里的某个人可能会发现我在代码中遗漏的一些明显的东西。

我发布了'清理'功能,负责分叉和放大修补 - 其余部分分成几个文件,所以希望这已经足够了。

(参数“name”是原始文件名,“newname”是修改后的副本。)

void cleanup (char * name, char * newname)
{
    if (pf)
    {
            pid_t patch_pid;

            char * const diffargs[5] = {thisdiff, "-u", newname, name, NULL};

            char * patchname = malloc(strlen(name) + 6);
            strcpy(patchname, name);
            strcat(patchname, ".patch");

            if((patch_pid = fork()) < 0 )
            {
                    printf("fork failed.\n%s\nfilecount: %ld\nopen forks: %d\n", strerror(errno), filecount, pcount);
                    exit(-1);
            }

            pcount++;

            if (patch_pid == 0)
            {
                    FILE *pfp;
                    if ((pfp = fopen(patchname, "w")) == NULL)
                    {
                            printf("Error opening file \"%s\" for writing.\n%s\n", patchname, strerror(errno));
                            exit(-1);
                    }

                    dup2(fileno(pfp), STDOUT_FILENO);
                    fclose(pfp);
                    execvp(diffargs[0], diffargs);
                    free(patchname);

                    if (remove(name) != 0)
                    {
                            printf("Error removing file %s\n%s\n", name, strerror(errno));
                            exit(-1);
                    }

                    if (rename(newname, name) != 0)
                    {
                            printf("Error renaming file %s\n%s\n", newname, strerror(errno));
                            exit(-1);
                    }
                    pcount--;
                    _exit(1);
            }
    }

    else if (!df && !xf)
    {
            if (remove(name) != 0)
            {
                    printf("Error removing file %s\n%s\n", name, strerror(errno));
                    exit(-1);
            }
            if (rename(newname, name) != 0)
            {
                    printf("Error renaming file %s\n%s\n", newname, strerror(errno));
                    exit(-1);
            }
    }
}

2 个答案:

答案 0 :(得分:0)

两个建议:

  1. 了解exec *()替换您的流程(如果成功)。跟随它的任何代码都无法访问。
  2. 使用wait *()函数之一获取已退出进程的退出状态;可能在SIGCHLD的信号处理程序中。
  3. 奖金建议:阅读W. Richard Stevens的 Unix环境下的高级编程;这是像这样的任务的圣经。

答案 1 :(得分:0)

您可能希望在else之后使用fork子句来处理父进程。像下面这样的东西可能会起作用;

void cleanup (char * name, char * newname)
{
    if (pf)
    {
        /* SNIP - unchanged */

        if (patch_pid == 0) /* child */
        {
            FILE *pfp;
            if ((pfp = fopen(patchname, "w")) == NULL)
            {
                printf("Error opening file \"%s\" for writing.\n%s\n",
                       patchname, strerror(errno));
                exit(EXIT_FAILURE);
            }
            dup2(fileno(pfp), STDOUT_FILENO);
            fclose(pfp);
            execvp(diffargs[0], diffargs);
            perror("execvp");
            exit(EXIT_FAILURE);
        }
        else /* parent */
        {
            pid_t rc;
            int stat;

            free(patchname);

            rc = waitpid(patch_pid, &stat, 0);
            if (rc < 0)
            {
                perror("waitpid");
                /* do something appropriate here */
            }
            else
            {
                /* if you care about your children */
                if (WIFEXITED(stat))
                {
                    printf("%d exited with status %d\n",
                           (int)rc, WEXITSTATUS(stat));
                }
                else if (WIFSIGNALED(stat))
                {
                    printf("%d terminated because of signal %d\n",
                           (int)rc, WTERMSIG(stat));
                }
                else if (WIFSTOPPED(stat))
                {
                    printf("%d was STOPPED with signal %d\n",
                           (int)rc, WSTOPSIG(stat));
                }
            }
            pcount--;

            if (remove(name) != 0)
            {
                printf("Error removing file %s\n%s\n", name, strerror(errno));
                exit(EXIT_FAILURE);
            }

            if (rename(newname, name) != 0)
            {
                printf("Error renaming file %s\n%s\n", newname, strerror(errno));
                exit(EXIT_FAILURE);
            }
        }
    }
}

我还强烈推荐已故的W. Richard Stevens在UNIX环境中阅读高级编程。实际上,您应该添加 UNIX网络编程第1卷和第1版。 2 也列入你的清单;)

我注意到的另一件事是你有与patchname相关的内存管理错误。 malloc调用未考虑字符串末尾的额外NUL字符。