【问题标题】:How to make multiple child processes increment and keep track of the same global variable如何使多个子进程递增并跟踪相同的全局变量
【发布时间】:2019-08-21 23:22:21
【问题描述】:

我的任务是制作一个分析文件/目录并提供有关它们的信息的程序。您可以设置递归标志来分析每个子目录。每个目录都由一个新进程分析(这是项目的要求),我想在每次找到新文件(SIGUSR2)或目录(SIGUSR1)时发送一个信号。在这些信号的处理程序中,我想增加跟踪程序找到的文件/目录数量的全局变量。我在使不同的进程增加相同的全局变量时遇到问题。我已经尝试过管道,但我似乎无法让它工作。

这是我分析目录的函数:

void process_dir(const ProgramConfig program_config, const char *dname, FILE *outstream)
{

  raise(SIGUSR1);

  /* Create a new process */
  pid_t pid = fork();

  if (pid == 0)
  {

    /* Child process */
    struct dirent *ent;
    DIR *dir;

    /* Open directory */
    if ((dir = opendir(dname)) != NULL)
    {
      /* Go through each file in this directory */
      while ((ent = readdir(dir)) != NULL)
      {
        /* Ignore anything that isn't a file or a directory */
        if (ent->d_type != DT_DIR && ent->d_type != DT_REG)
          continue;

        /* Ignore the '.' and '..' directories */
        if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
          continue;

        /* Prepend this directory name to file name */
        char name[256];
        strcpy(name, dname);
        strcat(name, "/");
        strcat(name, ent->d_name);

        if (ent->d_type == DT_DIR && program_config.r_flag)
        {
          /* Found a subdirectory, process it if -r flag enabled */
          process_dir(program_config, name, outstream);
        }
        else
        {
          /* Found a file, process it */
          process_file(program_config, name, outstream);
        }
      }
    }
    else
    {
      /* Error opening directory */
    }

    /* Exit from child process */
    exit(0);
  }
  else if (pid < 0)
  {
    /* Error creating process */
  }
  else
  {

    /* Parent process */
    wait(NULL);

    /* Log this event */
    if (program_config.v_flag)
    {
      char act[100];
      sprintf(act, "PROCESSED DIR %s", dname);
      log_event(act);
    }
  }
}

这是我的处理程序:

void sigusr1_handler(int sig)
{
  if (sig != SIGUSR1)
  {
    fprintf(stderr, "Wrong signal received! Expected: SIGUSR1\n");
  }

  dirsFound++;
  printf("New directory: %ld/%ld directories/files at this time.\n", dirsFound, filesFound);
}

void sigusr2_handler(int sig)
{
  if (sig != SIGUSR2)
  {
    fprintf(stderr, "Wrong signal received! Expected: SIGUSR2\n");
  }

  filesFound++;
}

使用线程不是此分配的选项。

【问题讨论】:

  • 您可能会发现在这里线程是比进程更实用的解决方案。
  • 我知道,我现在一直在学习线程。我忘了补充一点,这个项目的要求之一是为每个目录使用各种进程。所以线程不在等式中。
  • 同时使用来自多个线程或进程的同一个磁盘似乎是一个巨大的潜在性能问题......这就像家庭作业还是什么? :)
  • 是的,这是一个 uni 项目。
  • 好吧,尽管这可能是不明智的,但这可以通过一个共享内存映射文件和原子增量来解决......或者查看“kill”函数以向父级发送信号过程。

标签: c unix recursion fork posix


【解决方案1】:

如果每个子进程都发送一个信号,那么计数器不需要共享或“全局”。捕获来自子级的所有信号的信号处理程序可以递增它。如果程序的其他部分不需要检查它,它可能是一个static 局部变量。如果没有,它可能会被声明为static 到具有获取和设置它的所有函数的模块。

如果您希望多个进程递增同一个共享变量,您可能希望将来自&lt;stdatomic.h&gt; 的原子变量(例如atomic_int)放入您可能从shmget() 获得的共享内存中,然后递增它与atomic_fetch_add().

我不会写一个完整的解决方案,因为听起来你想自己解决这个作业问题。

【讨论】:

  • 我相信我想要的解决方案涉及管道,您认为这可能吗? (以一种不太复杂的方式)
  • 是的。经典的解决方案是在父进程中打开一对相互连接的管道,fork 以便子进程继承它们,然后在父进程中关闭一端,在子进程中关闭另一端。您可以使用poll()select() 来检查消息。
  • 如果你想传递来自多个子进程的消息,你可以试试消息队列。
【解决方案2】:

如果我的理解正确,您将在引发信号的同一进程中处理信号。因此,每个后代进程都会增加自己在特定子目录中找到的目录和文件的计数器。您需要做的是将最顶层的祖先进程 id 传递给它的所有后代,并将来自后代的信号发送到最顶层的祖先。有关向另一个进程发送信号的提示,请参阅 How to send a signal to a process in C?

【讨论】:

  • 我尝试保存主进程的 pid,然后使用 kill() 将信号发送到主进程而不是 raise() 但这让我得到了一些奇怪的结果
【解决方案3】:

我认为你可以使用命名信号量:

https://www.systutorials.com/docs/linux/man/7-sem_overview/

基本上跨进程打开同名信号量,sem_post 为自增,sem_getvalue 为取值。

【讨论】:

  • 我不被允许使用信号量,因为我还没有学会它们:/
  • @PedroAlves 我明白了,所以管道是分配的先决条件。如果有人遇到真正的问题,我会留下答案。祝你的任务好运!
猜你喜欢
  • 2018-07-25
  • 2011-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-15
  • 1970-01-01
相关资源
最近更新 更多