【问题标题】:Applying fork() and pipe() (or fifo()) on counting words code将 fork() 和 pipe()(或 fifo())应用于计数字代码
【发布时间】:2015-06-13 15:35:52
【问题描述】:

我终于写完了数字代码。它计算文件中的总字数。 (即txt)。现在,我想使用多个 fork() 来访问和读取每个文件。我上周学习了。此外,我使用全局变量来保存计数单词的数量。据我所知,如果我应用 fork(),使用的全局变量被分配为 0。为了避免它,我尝试使用 mmap() 和类似的函数,这很好。但是,我也想使用 pipe() (如果可能的话,fifo() )进行通信(保存数字值)。

我使用 nftw() 函数进入文件夹和文件。我的逻辑在下图中。如何在此代码上使用 fork() 和 pipe() (fifo()) ?由于我缺乏经验,fork() 对我来说真的很复杂。我是使用 pipe() 和 fork() 的新手。根据我的想法,代码的逻辑是如果我可以使用 fork() 和 pipe(),那么每个文件(即 txt)都会有 fork() 并通过使用 fork 访问它们。如果有另一个文件夹并且有文件,则再次从创建的 fork 之一创建 fork() ,然后访问 file.我试着解释一下下面的图。谢谢你。我想学习使用它们。

int countInEveryFolder(const char *dir)
使用

是因为我不知道如何计算文件,直到 nftw() 函数中的下一个文件夹。文件数量是必要的,因为它是 fork 的数量。

每个文件夹都应该是文件的父文件夹。文件包含在文件夹中。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <dirent.h>
#include <errno.h>
#include <ftw.h>
#include <ctype.h>
#include <sys/mman.h>
#include <locale.h>
#include <errno.h>



#define MAX_PATH_LEN        2048

unsigned long total_words = 0UL;
unsigned long total_dirs = 0UL;
unsigned long total_files = 0UL;


// Just proves counting number of file in a folder
int countInEveryFolder(const char *dir) {
    struct stat stDirInfo;
    struct dirent * stFiles;
    DIR * stDirIn;
    char szFullName[MAX_PATH_LEN];
    char szDirectory[MAX_PATH_LEN];
    struct stat stFileInfo;

    int numOfFile = 0;

        strncpy( szDirectory, dir, MAX_PATH_LEN - 1 );


    if (lstat( szDirectory, &stDirInfo) < 0)
    {
        perror (szDirectory);
        return 0;
    }
    if (!S_ISDIR(stDirInfo.st_mode))
        return 0;
    if ((stDirIn = opendir( szDirectory)) == NULL)
    {
        perror( szDirectory );
        return 0;
    }
    while (( stFiles = readdir(stDirIn)) != NULL)
    {
        if (!strcmp(stFiles->d_name, ".") || !strcmp(stFiles->d_name, ".."))
            continue;
        sprintf(szFullName, "%s/%s", szDirectory, stFiles -> d_name );

        if (lstat(szFullName, &stFileInfo) < 0)
            perror ( szFullName );

        /* is the file a directory? */
        if (S_ISREG(stFileInfo.st_mode))
        {
            printf( "Filename: %s\n", szFullName );
            numOfFile++;
        }

    }  // end while
    closedir(stDirIn);
    return numOfFile;
}




// Count words in files.
unsigned long count_words_in_file(const char *const filename)
{
    unsigned long count = 0UL;
    int errnum = 0;
    int c;
    FILE *in;

    in = fopen(filename, "rt");
    if (in == NULL) {
        errnum = errno;
        fprintf(stderr, "%s: %s.\n", filename, strerror(errnum));
        errno = errnum;
        return 0UL;
    }

    /* Skip leading whitespace. */
    do {
        c = getc(in);
    } while (isspace(c));

    /* Token loop. */
    while (c != EOF) {

        /* This token is a word, if it starts with a letter. */
        if (isalpha(c))
            count++;

        /* Skip the rest of this token. */
        while (!isspace(c) && c != EOF)
            c = getc(in);

        /* Skip the trailing whitespace. */
        while (isspace(c))
            c = getc(in);
    }

    /* Paranoid checking for I/O errors. */
    if (!feof(in) || ferror(in)) {
        fclose(in);
        fprintf(stderr, "Warning: %s: %s.\n", filename, strerror(EIO));
        errnum = EIO;
    } else
        if (fclose(in)) {
            fprintf(stderr, "Warning: %s: %s.\n", filename, strerror(EIO));
            errnum = EIO;
        }
    errno = errnum;

    return count;
}


// Recursively go in folders
int nftw_callback(const char *filepath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{

    // Directory
    if (typeflag == FTW_DP || typeflag == FTW_D)
    {

        total_dirs++;
        printf("%*s%s\n", ftwbuf->level * 4, "", filepath);
        //countInEveryFolder(filepath);

    }
    // Folder
    else if (typeflag == FTW_F)
    {
        total_files++;
        total_words += count_words_in_file(filepath);
        printf("%*s%s\n", ftwbuf->level * 4, "", filepath);
    }
    return 0;
}

/* Error message */
void err_sys(const char *msg)
{
    perror(msg);
    fflush(stdout);
    exit(EXIT_FAILURE);
}



int main(int argc, char *argv[])
{


    total_files = total_dirs = total_words = 0UL;
    if (nftw(argv[1], nftw_callback, 15, FTW_PHYS) == 0) {
        /* Success! */
        printf("%s: %lu files, %lu directories, %lu words total.\n",
               argv[1], total_files, total_dirs, total_words);

    } else {
        /* Failed... */
        err_sys("ntfw");
    }
    putchar('\n');



    //printf( "\nTotal words = %d\n\n", *wordCount);
    //printf( "\nTotal folders = %d\n\n", *folderCount);
    //printf( "\nTotal childs = %d\n\n", *childCount);      //fork()


    return 0;
}

【问题讨论】:

  • 你可以使用重量轻且容易的螺纹代替叉子,因为管道和所有这些东西。stackoverflow.com/questions/5514464/…
  • 我也会学习它,但现在是学习使用 fork() 和 pipe() 的时候了。 @sonukumar
  • 这是一个有趣的学习问题。然而,调用fork() 为每个count() 创建一个进程对于当前的操作系统来说开销太大,并且可能会导致系统崩溃(参见“Fork Bomb”)。更好的方法是为每个目录使用fork(),但这有类似的开销。更好的方法是fork() 数量等于系统上 CPU 数量的工作进程,让父进程递归扫描文件系统上的文件,并将这些文件路径添加到队列中。每个工人都会通过自己的pipe() 与父母沟通。
  • 我知道您这样做是出于学习目的,但作为旁注:fork()(或线程)不太可能提高性能。如果您的底层文件系统位于 HDD 上,则可能会导致性能下降。
  • @NewCoder pastebin.com/V6dvEFnP 检查它没有管道。Fork 用于每个文件。

标签: c linux pipe fork


【解决方案1】:

首先,我会分两个阶段编写程序。一个单进程阶段,其中所有文件路径都排队(进入链接列表或出队),以及一个多进程阶段,其中工作进程通过其pipe() 接收工作并将计数发送回主进程通过他们的pipe() 处理。主进程将使用select() 多路复用来自其子进程的输入。

一旦您了解如何将select()pipe()s 一起使用,就可以同时进行文件路径发现。

这种设计在Gonode.jsgreenlet 中使用 Python 实现起来会容易得多,但是在C 中学习如何实现它可以让您对您不使用的底层操作有一定程度的理解不要使用新的语言。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 1970-01-01
    相关资源
    最近更新 更多