Печать нечетных чисел с использованием сигналов - PullRequest
1 голос
/ 30 августа 2008

Мне нужно напечатать натуральные номера. 1,2, ... n так, что родительский процесс печатает все нечетные числа, а дочерний процесс печатает все четные числа, и все это должно быть сделано с использованием сигналов POSIX. Как мне это сделать?

Вывод должен быть:

Родитель: 1
Ребенок: 2
Родитель: 3
...

Ответы [ 2 ]

4 голосов
/ 05 октября 2008

Возможно, было бы более полезно, если бы вы предоставили то, что у вас есть, и объяснили, что работает не так, как ожидалось, но вот что я придумал:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

#define READY_SIGNAL SIGUSR1

/* The ready flag is set when READY_SIGNAL is received.
 * It is needed so that when we wake up from sigsuspend
 * we know whether or not the signal received was READY_SIGNAL. */
volatile sig_atomic_t ready;
void make_ready(int i) { ready = 1; }

int
main (int argc, char *argv[])
{
  pid_t cpid, ppid;  /* pids of the child and parent */
  /* Signal masks for sigprocmask and sigsuspend */
  sigset_t block_mask, wait_mask;
  unsigned long c = 1;   /* The counter */
  unsigned long n = 100; /* The default max count value */
  struct sigaction act;

  /* Override the default max count if provided */
  if (argv[1])
    n = strtoul(argv[1], NULL, 10);

  /* Prepare signal masks */
  sigemptyset(&wait_mask);
  sigemptyset(&block_mask);
  sigaddset(&block_mask, READY_SIGNAL);

  /* Set the signal mask for the parent to ignore READY_SIGNAL until
   * we are ready to receive it, the mask will be inherited by the child,
   * needed to avoid race conditions */
  sigprocmask(SIG_BLOCK, &block_mask, NULL);

  /* Register the signal handler, will be inherited by the child */
  act.sa_flags = 0;
  act.sa_handler = make_ready;
  sigemptyset(&act.sa_mask);
  sigaction(READY_SIGNAL, &act, NULL);

  /* Get the parent's process id, needed for the child to send signals
   * to the parent process, could alternatively use getppid in the child */
  ppid = getpid();

  /* Call fork, storing the child's process id needed for the parent to
   * send signals to the child */
  cpid = fork();

  if (cpid < 0) {
    perror("Fork failed");
    exit(EXIT_FAILURE);
  }

  if (cpid == 0) {
    /* Child */
    c = 2;  /* Child's first number will always be 2 */
    if (c > n) exit(0); /* If c > n we have nothing to do */

    do {
      /* Suspend until we receive READY_SIGNAL */
      while (!ready) sigsuspend(&wait_mask);

      /* Print out number, flush for proper output sequencing when output
         is not a terminal. */
      printf("Child: %lu\n", c);
      fflush(stdout);

      ready = 0; /* Reset ready flag */
      c += 2; /* Increment counter */

      /* Wake up parent process */
      kill(ppid, READY_SIGNAL);
    } while (c <= n);  
  } else {
    /* Parent */
    for (;;) {
      /* Print out number, flush for proper output sequencing when output
         is not a terminal. */
      printf("Parent: %lu\n", c);
      fflush(stdout);

      c += 2; /* Increment counter */

      kill(cpid, READY_SIGNAL); /* Wake up child process */

      if (c > n) break; /* Don't go back to sleep if we are done */

      ready = 0; /* Reset ready flag */

      /* Suspend until we receive READY_SIGNAL */
      while (!ready) sigsuspend(&wait_mask);
    };

    wait4(cpid, NULL, 0); /* Don't exist before child finishes */
  }

  return 0;
}

Это проходит эти основные тесты:

./print_with_signals 100000|sort -n -k 2 -c && echo "Success"
./print_with_signals 100001|sort -n -k 2 -c && echo "Success"

3 голосов
/ 02 октября 2008

Я думаю, что это домашнее задание было дано вам, чтобы вы попробовали много решений и самостоятельно пришли к выводу, что сигналы не являются хорошей техникой синхронизации .

Это бесценный урок, хорошо его запомни и теперь используй семафоры! :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...