Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用fork()遍历目录_C_Unix_Fork_Posix - Fatal编程技术网

C 使用fork()遍历目录

C 使用fork()遍历目录,c,unix,fork,posix,C,Unix,Fork,Posix,我尝试使用fork()进入文件夹并读取文件。我使用函数递归地进入文件夹。其基本思想是,在一个目录中有多个文件和目录。孩子们分别同时阅读每个文件。但是,如果有目录,则子目录将是读取文件的子目录的父目录 static int soner_each_time(const char *filepath, const struct stat *info, int typeflag, struct FTW *ftwinfo) { pid_t pid =

我尝试使用
fork()
进入文件夹并读取文件。我使用函数递归地进入文件夹。其基本思想是,在一个目录中有多个文件和目录。孩子们分别同时阅读每个文件。但是,如果有目录,则子目录将是读取文件的子目录的父目录

static int soner_each_time(const char *filepath, const struct stat *info,
                    int typeflag, struct FTW *ftwinfo)
{

    pid_t   pid = 0;
    char    buf[BUFSIZE];
    int     status;
    int     i = 0;

    /* The variables are related to functions of reading file  */

    int     totalLines;
    char    arr[TOTALNUMBEROFLINES][BUFSIZE];
    int     retval;


    const char *const filename = filepath + ftwinfo->base;

    if (( pid = fork()) < 0) {
        const int cause = errno;
        fprintf(stderr, "Fork error: %s\n", strerror(cause));
        errno = cause;
        return -1;
    }
    else if( pid > 0 ) // parent
    {
        if (typeflag == FTW_DP || typeflag == FTW_D)
        {
            sprintf(buf, "%*s%s\n\n", ftwinfo->level * 4, "", filepath);
            write(1, buf, strlen(buf));
            pid = wait(&status);
            if (pid == -1)
                perror("Failed to wait for child");
            else if (WIFEXITED(status) && !WEXITSTATUS(status))
                printf("parent [%d] reaped child [%d]\n", getpid(), pid);
            else if (WIFEXITED(status))
                printf("Child %ld terminated with return status %d\n",
                       (long)pid, WEXITSTATUS(status));
            else if (WIFSIGNALED(status))
                printf("Child %ld terminated due to uncaught signal %d\n",
                       (long)pid, WTERMSIG(status));
            else if (WIFSTOPPED(status))
                printf("Child %ld stopped due to signal %d\n",
                       (long)pid, WSTOPSIG(status));
        }
    }


    if (pid == 0) // child
    {
        if (typeflag == FTW_F)
        {
            sprintf(buf, "||| Child [%d] of parent [%d]: %s |||\n", getpid(), getppid(), filename);
            write(1, buf, strlen(buf));

            /* Both of them are about reading function */
            totalLines = storeLinesInArray(filename, arr);

            retval = for_each_file(filename, totalLines, key, arr);

            sprintf(buf, "||| Child [%d] of parent [%d] is about to exit |||\n", getpid(), getppid());
            write(1, buf, strlen(buf));
        }

        else if (typeflag == FTW_DP || typeflag == FTW_D)
        {
            sprintf(buf, "%*s%s\n\n", ftwinfo->level * 4, "", filepath);
            write(1, buf, strlen(buf));
        }

    }
        return 0;
}

你有一些虫子。下面是更正后的代码

孩子没有执行
exit
调用,因此它将继续自己的
nftw
,因此许多文件被冗余处理。我添加了退出(0)

fork
s的速度如此之快,以至于系统将耗尽可用的
pid
s

我添加了三件事来解决这个问题:

  • 一个“收获”例程,它在
    waitpid(0,&status,WNOHANG)
    上循环以捕获完成的子项
  • fork
    周围添加了一个循环,以捕获“插槽用完”问题
  • 添加了限制机制,将活动子级的数量限制为正常/有用的值
  • 我对源代码进行了注释,指出错误所在的位置

    虽然不是硬bug,但为每个文件执行
    fork
    会增加大量开销。磁盘带宽将被大约四个活动的子线程所饱和,因此使用更多的子线程只会降低速度。为目录派生一个子目录没有多大作用,因为“有意义”的处理将是针对文件的

    不管怎样,下面是更正后的代码[请原谅这种不必要的风格清理]:

    #define _POSIX_C_SOURCE 200809L
    #define _XOPEN_SOURCE 700
    #include <unistd.h>
    #include <dirent.h>
    #include <stdlib.h>
    #include <locale.h>
    #include <string.h>
    #include <errno.h>
    #include <ftw.h>
    #include <stdio.h>
    #include <sys/wait.h>
    
    #define TOTALNUMBEROFLINES 1000
    #define BUFSIZE 1000
    
    // output verbose/debug messages
    int opt_v;
    
    // limit of number of children that can be used at one time (if non-zero)
    int opt_T;
    
    int pendcnt;                            // number of active children
    
    void
    err_sys(const char *const str)
    {
        perror(str);
        fflush(stdout);
        exit(1);
    }
    
    int
    storeLinesInArray(const char *file, char lines[][BUFSIZE])
    {
        return 0;
    }
    
    static int
    for_each_file(const char *filepath, int totalLines, const char *key, const char arr[][BUFSIZE])
    {
    
        fprintf(stdout, "File name is = %s\n", filepath);
        fflush(stdout);
    
        return 0;
    }
    
    // reap_some -- reap a few processes
    int
    reap_some(int final)
    {
        pid_t pid;
        int status;
        int reapcnt;
    
        reapcnt = 0;
    
        // reap all completed children
        while (1) {
            pid = waitpid(0,&status,WNOHANG);
            if (pid == 0)
                break;
    
            if (pid == -1) {
                if (errno != ECHILD)
                    perror("Failed to wait for child");
                break;
            }
    
            if (WIFSIGNALED(status)) {
                printf("Child %ld terminated due to uncaught signal %d\n",
                    (long) pid, WTERMSIG(status));
                ++reapcnt;
                continue;
            }
    
            if (WIFSTOPPED(status)) {
                printf("Child %ld stopped due to signal %d\n",
                    (long) pid, WSTOPSIG(status));
                continue;
            }
    
            if (WIFEXITED(status)) {
                ++reapcnt;
                if (WEXITSTATUS(status) == 0) {
                    if (opt_v)
                        printf("parent [%d] reaped child [%d]\n", getpid(), pid);
                }
                else
                    printf("Child %ld terminated with return status %d\n",
                        (long) pid, WEXITSTATUS(status));
                continue;
            }
        }
    
        // bump down the number of children that are "in-flight"
        pendcnt -= reapcnt;
    
        return reapcnt;
    }
    
    static int
    soner_each_time(const char *filepath, const struct stat *info, int typeflag, struct FTW *ftwinfo)
    {
        pid_t pid = 0;
        char *bp;
        int lvl;
        char buf[BUFSIZE];
    
        /* The variables are related to functions of reading file */
    
        int totalLines;
        char arr[TOTALNUMBEROFLINES][BUFSIZE];
        int retval;
    
        const char *const filename = filepath + ftwinfo->base;
    
        switch (typeflag) {
        case FTW_DP:
        case FTW_D:
            bp = buf;
            for (lvl = 0;  lvl < ftwinfo->level;  ++lvl)
                bp += sprintf(bp,"    ");
            bp += sprintf(bp, "%s\n\n",filepath);
            write(1, buf, strlen(buf));
            //reap_some(0);
            break;
    
        case FTW_F:
            // BUGFIX:
            // limit the number of in-flight children
            // too many children serves no purpose -- they saturate the system
            // resources and performance actually goes _down_ because the system
            // spends more time doing context switches between them than the actual
            // work. more than a few children to process files produces little
            // benefit after the disk I/O is running at maximum
            if (opt_T) {
                while (pendcnt > opt_T)
                    reap_some(0);
            }
    
            // BUGFIX:
            // without a throttle, we spawn children so fast we're going to get
            // [many] failures here (i.e. we use up _all_ available pids)
            while (1) {
                pid = fork();
                if (pid >= 0)
                    break;
                reap_some(0);
            }
    
            // parent
            // keep track of the child count
            if (pid > 0) {
                ++pendcnt;
                break;
            }
    
            // child
            sprintf(buf, "||| Child [%d] of parent [%d]: %s |||\n",
                getpid(), getppid(), filename);
            if (opt_v)
                write(1, buf, strlen(buf));
    
            /* Both of them are about reading function */
            totalLines = storeLinesInArray(filename, arr);
    
            retval = for_each_file(filename, totalLines, "not needed now", arr);
    
            sprintf(buf, "||| Child [%d] of parent [%d] is about to exit (RETVAL: %d) |||\n", getpid(), getppid(), retval);
            if (opt_v)
                write(1, buf, strlen(buf));
    
            // BUGFIX:
            // child won't exit without this -- causing multiple children to redo
            // the same files (i.e. they would continue the nftw -- only parent
            // should do that)
            exit(0);
            break;
        }
    
        return 0;
    }
    
    int
    main(int argc, char **argv)
    {
        char *cp;
    
        --argc;
        ++argv;
    
        opt_T = 10;
    
        for (;  argc > 0;  --argc, ++argv) {
            cp = *argv;
            if (*cp != '-')
                break;
    
            switch (cp[1]) {
            case 'T':  // throttle
                cp += 2;
                opt_T = (*cp != 0) ? atoi(cp) : 0;
                break;
            case 'v':  // verbose messages
                opt_v = 1;
                break;
            }
        }
    
        cp = *argv;
        printf("opt_T=%d opt_v=%d -- %s\n",opt_T,opt_v,cp);
        sleep(3);
        printf("away we go ...\n");
    
        if (nftw(cp, soner_each_time, 15, FTW_CHDIR)) {
            fprintf(stderr, "Failed directory.\n");
            exit(1);
        }
    
        // wait for all children to complete
        while (pendcnt > 0)
            reap_some(1);
    
        return 0;
    }
    

    “有一些东西我不能得到它分叉多个一对一的文件”。这到底是什么意思?也许这有助于给出预期行为和实际行为的具体例子。我编辑了问题@kaylumNot,甚至不知道从哪里开始。。。您有一个
    状态
    变量,您测试该变量,但从未设置;您似乎正在检查子状态,而没有等待子状态完成。您需要发布一个完整的可编译示例-一个@snr,因为StackOverflow通常就是这样工作的(请阅读MVCE链接)。如果我能运行你的代码,我可能会很快告诉你它出了什么问题;如果我不能运行你的代码,我可能不会费心在脑子里想出来。(注意,你的例子也应该是最少的。正如链接所说,减少它通常会帮助你自己解决问题)。你能发布你最新的完整代码吗。为了不把问题搞砸,把它放在像pastebin这样的东西上,然后在这里的评论中发布链接。我来看看。
    #define _POSIX_C_SOURCE 200809L
    #define _XOPEN_SOURCE 700
    #include <unistd.h>
    #include <dirent.h>
    #include <stdlib.h>
    #include <locale.h>
    #include <string.h>
    #include <errno.h>
    #include <ftw.h>
    #include <stdio.h>
    #include <sys/wait.h>
    
    #define TOTALNUMBEROFLINES 1000
    #define BUFSIZE 1000
    
    // output verbose/debug messages
    int opt_v;
    
    // limit of number of children that can be used at one time (if non-zero)
    int opt_T;
    
    int pendcnt;                            // number of active children
    
    void
    err_sys(const char *const str)
    {
        perror(str);
        fflush(stdout);
        exit(1);
    }
    
    int
    storeLinesInArray(const char *file, char lines[][BUFSIZE])
    {
        return 0;
    }
    
    static int
    for_each_file(const char *filepath, int totalLines, const char *key, const char arr[][BUFSIZE])
    {
    
        fprintf(stdout, "File name is = %s\n", filepath);
        fflush(stdout);
    
        return 0;
    }
    
    // reap_some -- reap a few processes
    int
    reap_some(int final)
    {
        pid_t pid;
        int status;
        int reapcnt;
    
        reapcnt = 0;
    
        // reap all completed children
        while (1) {
            pid = waitpid(0,&status,WNOHANG);
            if (pid == 0)
                break;
    
            if (pid == -1) {
                if (errno != ECHILD)
                    perror("Failed to wait for child");
                break;
            }
    
            if (WIFSIGNALED(status)) {
                printf("Child %ld terminated due to uncaught signal %d\n",
                    (long) pid, WTERMSIG(status));
                ++reapcnt;
                continue;
            }
    
            if (WIFSTOPPED(status)) {
                printf("Child %ld stopped due to signal %d\n",
                    (long) pid, WSTOPSIG(status));
                continue;
            }
    
            if (WIFEXITED(status)) {
                ++reapcnt;
                if (WEXITSTATUS(status) == 0) {
                    if (opt_v)
                        printf("parent [%d] reaped child [%d]\n", getpid(), pid);
                }
                else
                    printf("Child %ld terminated with return status %d\n",
                        (long) pid, WEXITSTATUS(status));
                continue;
            }
        }
    
        // bump down the number of children that are "in-flight"
        pendcnt -= reapcnt;
    
        return reapcnt;
    }
    
    static int
    soner_each_time(const char *filepath, const struct stat *info, int typeflag, struct FTW *ftwinfo)
    {
        pid_t pid = 0;
        char *bp;
        int lvl;
        char buf[BUFSIZE];
    
        /* The variables are related to functions of reading file */
    
        int totalLines;
        char arr[TOTALNUMBEROFLINES][BUFSIZE];
        int retval;
    
        const char *const filename = filepath + ftwinfo->base;
    
        switch (typeflag) {
        case FTW_DP:
        case FTW_D:
            bp = buf;
            for (lvl = 0;  lvl < ftwinfo->level;  ++lvl)
                bp += sprintf(bp,"    ");
            bp += sprintf(bp, "%s\n\n",filepath);
            write(1, buf, strlen(buf));
            //reap_some(0);
            break;
    
        case FTW_F:
            // BUGFIX:
            // limit the number of in-flight children
            // too many children serves no purpose -- they saturate the system
            // resources and performance actually goes _down_ because the system
            // spends more time doing context switches between them than the actual
            // work. more than a few children to process files produces little
            // benefit after the disk I/O is running at maximum
            if (opt_T) {
                while (pendcnt > opt_T)
                    reap_some(0);
            }
    
            // BUGFIX:
            // without a throttle, we spawn children so fast we're going to get
            // [many] failures here (i.e. we use up _all_ available pids)
            while (1) {
                pid = fork();
                if (pid >= 0)
                    break;
                reap_some(0);
            }
    
            // parent
            // keep track of the child count
            if (pid > 0) {
                ++pendcnt;
                break;
            }
    
            // child
            sprintf(buf, "||| Child [%d] of parent [%d]: %s |||\n",
                getpid(), getppid(), filename);
            if (opt_v)
                write(1, buf, strlen(buf));
    
            /* Both of them are about reading function */
            totalLines = storeLinesInArray(filename, arr);
    
            retval = for_each_file(filename, totalLines, "not needed now", arr);
    
            sprintf(buf, "||| Child [%d] of parent [%d] is about to exit (RETVAL: %d) |||\n", getpid(), getppid(), retval);
            if (opt_v)
                write(1, buf, strlen(buf));
    
            // BUGFIX:
            // child won't exit without this -- causing multiple children to redo
            // the same files (i.e. they would continue the nftw -- only parent
            // should do that)
            exit(0);
            break;
        }
    
        return 0;
    }
    
    int
    main(int argc, char **argv)
    {
        char *cp;
    
        --argc;
        ++argv;
    
        opt_T = 10;
    
        for (;  argc > 0;  --argc, ++argv) {
            cp = *argv;
            if (*cp != '-')
                break;
    
            switch (cp[1]) {
            case 'T':  // throttle
                cp += 2;
                opt_T = (*cp != 0) ? atoi(cp) : 0;
                break;
            case 'v':  // verbose messages
                opt_v = 1;
                break;
            }
        }
    
        cp = *argv;
        printf("opt_T=%d opt_v=%d -- %s\n",opt_T,opt_v,cp);
        sleep(3);
        printf("away we go ...\n");
    
        if (nftw(cp, soner_each_time, 15, FTW_CHDIR)) {
            fprintf(stderr, "Failed directory.\n");
            exit(1);
        }
    
        // wait for all children to complete
        while (pendcnt > 0)
            reap_some(1);
    
        return 0;
    }
    
    // pseudo -- loose pseudo-code for non-nftw method
    //
    // NOTES:
    // (1) pendcnt must now be a _shared_ memory variable (e.g. shmget, etc)
    // (2) access must be locked by a shared memory semaphore
    // (3) we must now have a list of our outstanding children
    // (4) we can no longer do a blind waitpid(0,&status,WNOHANG) as we need to
    //     keep track of when our direct children complete
    
    struct entfile {
        struct dirent ent;
        struct stat st;
    };
    
    // dodir -- enter/exit directory and perform all actions
    void
    dodir(const char *subdir)
    {
        // NOTE: you can create a wrapper struct for this that also has stat
        struct entfile dirlist[1000];
    
        // add subdir to directory stack ...
        dirstack_push(subdir);
    
        // enter directory
        chdir(subdir);
    
        // do whatever you'd like ...
        process_directory(subdir);
    
        // open directory
        dirctl = opendir(".");
    
        // pre-save all entries [skipping "." and ".."]
        // this prevents too many open directory descriptors
        // NOTE: we should stat(2) the file if d_type not supported
        while (1) {
            dirent = readdir(dirctl);
            stat(dirent->d_name,&st);
            add_to_dirent_list(dirlist,dirent,&st);
        }
    
        // close directory _before_ we process any entries
        closedir(dirctl);
    
        // process all file entries -- pre-order
        for (ALL_IN_DIRLIST(ent,dirlist)) {
            if (ent->ent.d_type == ISFILE)
                doentry(ent);
        }
        wait_for_all_on_pendlist();
    
        // process all directory entries -- pre-order
        for (ALL_IN_DIRLIST(dirent,dirlist)) {
            if (ent->ent.d_type == ISDIR)
                doentry(ent);
        }
        wait_for_all_on_pendlist();
    
        // remove directory from stack
        dirstack_pop();
    
        // exit directory
        chdir("..")
    }
    
    // doentry -- process a directory entry
    void
    doentry(struct entfile *ent)
    {
        char *tail;
    
        tail = ent->ent.d_name;
    
        do {
            // does throttle, etc.
            pid = forkme();
    
            // parent
            // see notes above
            if (pid) {
                // NOTE: these semaphore waits can be costly
                sem_wait();
                ++pendcnt;
                sem_post();
    
                add_pid_to_pendlist(pid,tail,...);
                break;
            }
    
            // child
            switch (ent->st.st.st_mode & ...) {
            case ISFILE:
                process_file(tail);
                break;
            case ISDIR:
                dodir(tail);
                break;
            }
    
            exit(0);
        } while (0);
    }
    
    // wait for immediate children
    void
    wait_for_all_on_pendlist(void)
    {
    
        while (MORE_IN_PENDLIST) {
            for (FORALL_IN_PENDLIST(tsk)) {
                pid = waitpid(tsk->pid,&tsk->status,WNOHANG);
    
                // check status like reap_some
                if (pid > 0)
                    remove_pid_from_pendlist(tsk);
            }
        }
    }