Как сделать так, чтобы несколько дочерних процессов увеличивали и отслеживали одну и ту же глобальную переменную - PullRequest
2 голосов
/ 31 марта 2019

Мне было поручено создать программу, которая анализирует файл / каталог и предоставляет информацию о них. Вы можете установить флаг рекурсии для анализа каждого подкаталога. Каждый каталог анализируется новым процессом (это требование проекта), и я хочу отправлять сигнал каждый раз, когда обнаруживается новый файл (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++;
}

Использование потоков не подходит для этого назначения.

Ответы [ 3 ]

0 голосов
/ 31 марта 2019

Если я получу, если правильно, вы обрабатываете сигналы в том же процессе, который их вызывает.В результате каждый процесс-потомок увеличивает свой собственный счетчик каталогов и файлов, найденных в определенном подкаталоге.Что вам нужно сделать, это передать идентификатор процесса самого верхнего предка всем его потомкам и отправить сигналы от потомков к самому главному предку.См. Как отправить сигнал процессу в C? для подсказок по отправке сигналов другому процессу.

0 голосов
/ 31 марта 2019

Вы можете использовать именованные семафоры, я думаю:

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

По сути, откройте семафор с одинаковыми именами во всех процессах, sem_post для увеличения, sem_getvalue для получения значения.

0 голосов
/ 31 марта 2019

Если каждый дочерний процесс отправляет сигнал, счетчик не должен быть общим или «глобальным». Обработчик сигналов, который отлавливает все сигналы от детей, может увеличивать его. Если никакая другая часть программы не нуждается в проверке, это может быть локальная переменная static. Если нет, он может быть объявлен как static для модуля со всеми функциями, которые его получают и устанавливают.

Если вы хотите, чтобы несколько процессов увеличивали одну и ту же общую переменную, вы хотели бы поместить атомную переменную из <stdatomic.h>, такую ​​как atomic_int, в разделяемую память, которую вы можете получить из shmget(), и увеличить это с atomic_fetch_add().

Я не буду писать полное решение, потому что, похоже, вы сами решаете эту домашнюю проблему.

...