The problem is to print natural nos. 1,2,...n such that the parent process prints all odd numbers and child all even numbers using POSIX signals. Output should be: Parent : 1 Child : 2 Parent : 3 and so on...any suggestions?
A:
yes...and will help me understand signals better. I have read the chapter on signals in Linux System Programming by Robert Love but I am not able to solve it. The problem is inspite of writing a signal handler the parent terminates. So I guess there is some problem in my logic.
Sushant
2008-08-29 22:01:10
If the parent terminates, my guess would be that you are not having a problem with the signals, but instead launching the child and having the parent continue. Try a simple parent/child that each just wait thirty seconds, then stop. Once that works, your main program may go better.
piCookie
2008-10-02 16:04:05
+3
A:
It would probably be more beneficial for you provide what you have so far and explain what doesn't work as expected but here is what I came up with:
#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;
}
This passes these basic tests:
./print_with_signals 100000|sort -n -k 2 -c && echo "Success"
./print_with_signals 100001|sort -n -k 2 -c && echo "Success"
Robert Gamble
2008-10-05 04:41:43