使用信号打印奇偶数字
时间:2020-03-05 18:45:16 来源:igfitidea点击:
我需要打印自然编号。 1,2,... n,这样父进程将打印所有奇数,而子进程将打印所有偶数,所有这些都需要使用POSIX信号来完成。我将如何实现这一目标?
输出应为:
父母:1
小孩:2
父母:3
...
解决方案
回答
我认为已将这项作业分配给我们,以使我们尝试许多解决方案,并自己得出结论,信号不是一种好的同步技术。
这是非常宝贵的一课,请记住并从现在开始使用信号灯! :)
回答
如果我们提供到目前为止所拥有的内容,并说明哪些内容无法按预期工作,但这可能是更有益的,但是我想出了以下几点:
#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"