Synchronising N sibling processes after fork - c

I'm having some hard time with synchronising N child process waiting each one of them to arrive at some specific point.
I've tried semaphores and signals but I can't get my head around it.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/msg.h>
#define NUM_KIDS 4
void handle(int signum);
int main(int argc, char const *argv[])
{
sem_t* sem;
sem = sem_open("/ok", O_CREAT, 0);
signal(SIGUSR1, handle);
for(int i = 0; i < NUM_KIDS; i++) {
switch(fork()) {
case 0:
fprintf(stderr, "ready %d from %d\n", getpid(), getppid());
/* i would like that each child stop here untill everyone is ready */
for(int j = 0; j < 10; j++)
fprintf(stderr, "lot of stuff\n");
exit(0);
break;
default:
/* unleashing the kids when everyone is ready */
wait(NULL);
fprintf(stderr, "OK\n");
break;
}
}
return 0;
}
void handle(int signum) {;}
And I believe that the output should be (once the child are sync)
ready ... from xxx
ready ... from xxx
ready ... from xxx
ready ... from xxx
...lots of stuff... 10 times
...lots of stuff... 10 times
...lots of stuff... 10 times
...lots of stuff... 10 times

Synchronization
There's a simple trick:
Create a pipe before you fork anything.
Have the children each close the write end of the pipe.
Have the children read from the pipe when you want to synchronize them.
Have the parent close both ends of the pipe when the children should be started.
Have the children close the read end of the pipe when they're released, so that the resources are released.
The children now do 'their thing' (grow up, produce output, die).
The parent now waits for its children to die (it's a morbid business when you're playing with processes on Unix).
If done correctly, the children all get EOF (zero bytes read) at the same time because there's no longer any process that can write to the pipe. (That's why it is important for the children to close the write end of the pipe before doing the synchronizing read().)
If you want the parent to know that the children are all ready, create two pipes before forking anything. The parent process closes the write end of this second pipe, and then reads from the read end. The children all close both ends of the pipe before settling into their read() call on the first pipe. The parent process gets EOF when all the children have closed the write end of the pipe, so it knows the children have all started, at least as far as closing the second pipe. The parent can then close the first pipe to release the children (and close the read end of the second pipe).
Don't wait too soon!
You are waiting in the default clause of the switch, which is not correct. You need all four child processes launched before you do any waiting — otherwise they'll never all be able to synchronize. When you do wait, you'll need to do your waiting in a (new) loop. And, while debugging, you should add print statements to identify what is going on in the parent process. For example, you'll print the status of the processes that exit, and their PID:
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("%d: child %d exited with status 0x%.4X\n", (int)getpid(), corpse, status);
Working code
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#define NUM_KIDS 4
int main(void)
{
int p_pipe[2];
int c_pipe[2];
char c;
if (pipe(p_pipe) != 0 || pipe(c_pipe) != 0)
{
fprintf(stderr, "Oops: failed to create pipes\n");
return 1;
}
for (int i = 0; i < NUM_KIDS; i++)
{
switch (fork())
{
case 0:
fprintf(stderr, "ready %d from %d\n", (int)getpid(), (int)getppid());
close(p_pipe[0]);
close(p_pipe[1]);
close(c_pipe[1]);
read(c_pipe[0], &c, 1);
close(c_pipe[0]);
for (int j = 0; j < 10; j++)
fprintf(stderr, "lot of stuff\n");
return NUM_KIDS + i;
case -1:
fprintf(stderr, "failed to fork child %d\n", i+1);
return 1;
default:
break;
}
}
close(p_pipe[1]);
read(p_pipe[0], &c, 1);
printf("%d: %d children started\n", (int)getpid(), NUM_KIDS);
close(c_pipe[0]);
close(c_pipe[1]);
int corpse;
int status;
while ((corpse = wait(&status)) >= 0)
printf("%d: child %d exited with status 0x%.4X\n", (int)getpid(), corpse, status);
return 0;
}
Sample run
ready 81949 from 81948
ready 81950 from 81948
ready 81951 from 81948
ready 81952 from 81948
81948: 4 children started
lot of stuff
lot of stuff
lot of stuff
lot of stuff
…lines omitted for brevity…
lot of stuff
lot of stuff
lot of stuff
lot of stuff
81948: child 81951 exited with status 0x0600
81948: child 81952 exited with status 0x0700
81948: child 81950 exited with status 0x0500
81948: child 81949 exited with status 0x0400

Related

why the waitpid() do not wait for child process?

There's my test code below. I expect the output should print out all the child processes created before parent process terminates, but it does not. Please tell me why.
In the test code, it creates 10 processes and waits for them again and again. I want the program to run on the condition that I have at most 10 processes at the same time.
My platform is Linux.
//#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>
//using namespace std;
void sig_chld(int signo)
{
pid_t pid;
int stat;
pid=wait(&stat);
fprintf(stderr, "child [%d] terminate\n",pid);
return;
}
int main(){
signal(SIGCHLD,sig_chld);
pid_t PID,old;
for(int i=0;i<1000;i++){
fprintf(stderr, "i == %d\n",i);
PID = fork();
switch(PID){
case -1:
fprintf(stderr, "fork fail");
break;
case 0:
exit(0);
break;
default:
if(i==0)old=PID;
if(i%100==99){
fprintf(stderr, "start waiting child [%d] with i = %d --------------------\n",old,i);
waitpid(old,NULL,0);
old = PID;
}
fprintf(stderr, "child [%d] create\n",PID);
}
}
fprintf(stderr, "final waiting for [%d] \n",PID);
waitpid(PID,NULL,0);
fprintf(stderr, "parent end\n");
return 0;
}
Below are the last few lines of the output. There are still a lot processes that don't terminate.
i == 992
child [13805] create
i == 993
child [13806] create
i == 994
child [13636] terminate
child [13637] terminate
child [13640] terminate
child [13810] create
i == 995
child [13811] create
i == 996
child [13812] create
i == 997
child [13642] terminate
child [13643] terminate
child [13814] create
i == 998
child [13645] terminate
child [13646] terminate
child [13816] create
i == 999
start waiting child [13666] with i = 999 --------------------
child [13817] create
final waiting for [13817]
child [13647] terminate
child [13648] terminate
child [13649] terminate
parent end

How to use pipes and signals correctly at the same time?

I have 2 children, and I want to send signals from children to parent, and an answer (random number, why? why not...) named pipe from the parent to each child.
I have this code:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#define WRITE(Str) (void)write(1,Str,strlen(Str))
void handler(int signumber)
{
WRITE("Signal arrived\n");
}
int main(){
/*random number */
srand(time(NULL)); //random number
int r = rand() % 2; //random number between 0 and 1
char original1[]="rdnr: ";
original1[6]=r+'0';
r = rand() % 2;
char original2[]="rdnr: ";
original2[6]=r+'0';
/*pipe, named pipe*/
int pid,fd,fd2;
printf("Fifo start!\n");
int fid=mkfifo("fifo.ftc", S_IRUSR|S_IWUSR ); // creating named pipe file
int fid2=mkfifo("fifo2.ftc", S_IRUSR|S_IWUSR );
if (fid==-1) //error handling
{
printf("Error at fid number: %i",errno);
exit(EXIT_FAILURE);
}
if (fid2==-1) //error handling
{
printf("Error at fid2 number: %i",errno);
exit(EXIT_FAILURE);
}
printf("Pipe system OK!\n");
/*signal*/
sigset_t sigset;
sigemptyset(&sigset); //empty signal set
sigaddset(&sigset,SIGTERM); //SIGTERM is in set
//sigfillset(&sigset); //each signal is in the set
sigprocmask(SIG_BLOCK,&sigset,NULL); //signals in sigset will be blocked
signal(SIGTERM,handler); //signal and handler is connetcted
signal(SIGUSR1,handler);
pid_t child2;
pid_t child=fork();
if (child>0)
{
child2 = fork();
if(child2>0){
printf("Parent, wainting for signal...\n");
sigsuspend(&sigset);
sigprocmask(SIG_UNBLOCK,&sigset,NULL);
int status;
wait(&status);
printf("Parent got 2 signal!\n");
printf("Parent will send 2 random number: %s and %s\n", original1, original2);
fd=open("fifo.ftc",O_WRONLY);
write(fd,original1,12);
close(fd);
fd2=open("fifo2.ftc",O_WRONLY);
write(fd2,original2,12);
close(fd2);
printf("Parent has sent the numbers!\n");
}
else{
printf("I'm child2.\n");
printf("child2 signalnr: %i (it is not blocked)\n", SIGUSR1);
kill(getppid(),SIGUSR1);
/*get pipe*/
sleep(5);
char s[1024]="nothn";
printf("got on pipe, in child2: %d!\n",fid);
fd=open("fifo.ftc",O_RDONLY);
read(fd,s,sizeof(s));
printf("got this on pipe, by child2: %s \n",s);
close(fd);
// remove fifo.ftc
unlink("fifo.ftc");
}
}
else
{
printf("I'm child1.\n");
printf("child1 signal nr: %i (it is blocked)\n",SIGTERM);
sleep(3);
kill(getppid(),SIGTERM);
//sleep(5);
/*get pipe*/
char s[1024]="nothn";
printf("Got this on pipe, by child1: %d!\n",fid2);
fd2=open("fifo2.ftc",O_RDONLY);
read(fd2,s,sizeof(s));
printf("got this inpipe fd2: %s by child2 \n",s);
close(fd2);
// remove fifo2.ftc
unlink("fifo2.ftc");
}
return 0;
}
And the pipes, and the signals work correctly if I use them separately, but together, here, not.
I got only this:
Fifo start!
Error at fid number: 17
by error handlers.
How can I use correctly the pipes and the signals at the same time?
UPDATE:
I've rethinked the parent as was mentioned in the comment section, now the output, what I can see is:
Fifo start!
Pipe system OK!
Parent, wainting for signal...
I'm child2.
I'm child1.
child1 signal nr: 15 (it is blocked)
child2 signalnr: 10 (it is not blocked)
Handled signal nr: 10
Got this on pipe, by child1: 0!
Handled signal nr: 15
got on pipe, in child2: 0!
So, the problem as I see is, the child process can't wait for the pipes, how can I solve this?
UPDATE2:
If I delete
int status;
wait(&status);
from the parent then works fine, just nothing is the to ensure the second signal arrives before the pipe things.
One repeating error in your code:
char original1[]="rdnr: ";
original1[6]=r+'0';
sizeof original1 is 7, the character at index 6 is the zero terminator of the string. By overwriting the zero terminator with r+'0' you destroy the string property of the array, so that you can no longer use strlen on it.
Fix:
char original1[] = "rdnr: 0";
original1[sizeof original1 - 2] += r;

Working with pipes in Unix C

I am having serious trouble working with pipes in C. I'm supposed to take in arguments from the command line (example: ./myprogram 123 45 67), read the arguments one character at a time into a buffer, send the character to the child process to be counted, and then return the total number of characters read to the parent process. My code is as follows(note: the comments are what I'm supposed to be doing):
// Characters from command line arguments are sent to child process
// from parent process one at a time through pipe.
// Child process counts number of characters sent through pipe.
// Child process returns number of characters counted to parent process.
// Parent process prints number of characters counted by child process.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
static int toChild[2];
static int fromChild[2];
static char buffer;
int main(int argc, char **argv)
{
int status;
int nChars = 0;
pid_t pid;
pipe(toChild);
pipe(fromChild);
if ((pid = fork()) == -1) {
printf("fork error %d\n", pid);
return -1;
}
else if (pid == 0) {
close(toChild[1]);
close(fromChild[0]);
// Receive characters from parent process via pipe
// one at a time, and count them.
int count = 0;
printf("child about to read\n");
while(read(toChild[0], &buffer, 1)){
count++;
}
// Return number of characters counted to parent process.
write(fromChild[1], &count, sizeof(count));
close(toChild[0]);
close(fromChild[1]);
printf("child exits\n");
}
else {
close(toChild[0]);
close(fromChild[1]);
// -- running in parent process --
printf("CS201 - Assignment 3 - Chris Gavette\n");
write(toChild[1], &argv[1], 1);
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
read(fromChild[0], &nChars, 1);
// Wait for child process to return. Reap child process.
// Receive number of characters counted via the value
// returned when the child process is reaped.
close(toChild[1]);
close(fromChild[0]);
waitpid(pid, &status, 0);
printf("child counted %d chars\n", nChars);
printf("parent exits\n");
return 0;
}
}
The child process seems to hang even though I've closed both ends of both pipes.
For starters, this is wrong.
write(toChild[1], &count, 1)
It will eventually contribute to your problem. count is a int, not char or unsigned char. You need to send sizeof(count). Also, the read-function upon hitting an error will return EOF, which is non-zero, so your child exit condition is not appropriate. it should look something like this:
while(read(toChild[0], &buffer, 1) == 1)
Finally, your parent process should cycle through each argument in argv[] sending each as a strlen sized buffer.
I'm nearly certain this is what you're trying to do. Note that in order to maintain sanity in knowing which descriptor is used for a specific purpose, I prefer using a #define to note what each process uses for reading and writing. This can be extended to any number of processes, btw, which I'm sure is not too far down the line for your next assignment:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
// P0_READ - parent read source
// P0_WRITE - parent write target
// P1_READ - child read source
// P1_WRITE - child write target
#define P0_READ 0
#define P1_WRITE 1
#define P1_READ 2
#define P0_WRITE 3
#define N_PIPES 4
int main(int argc, char **argv)
{
int fd[N_PIPES], count = 0, i;
pid_t pid;
char c;
if (pipe(fd) || pipe(fd+2))
{
perror("Failed to open pipe(s)");
return EXIT_FAILURE;
}
// fork child process
if ((pid = fork()) == -1)
{
perror("Failed to fork child process");
return EXIT_FAILURE;
}
// child process
if (pid == 0)
{
// close non P1 descriptors
close(fd[P0_READ]);
close(fd[P0_WRITE]);
// get chars from input pipe, counting each one.
while(read(fd[P1_READ], &c, 1) == 1)
count++;
printf("Child: count = %d\n", count);
write(fd[P1_WRITE], &count, sizeof(count));
// close remaining descriptors
close(fd[P1_READ]);
close(fd[P1_WRITE]);
return EXIT_SUCCESS;
}
// parent process. start by closing unused descriptors
close(fd[P1_READ]);
close(fd[P1_WRITE]);
// send each arg
for (i=1; i<argc; ++i)
write(fd[P0_WRITE], argv[i], strlen(argv[i]));
// finished sending args
close(fd[P0_WRITE]);
// Wait for child process to return.
wait(NULL);
// wait for total count
if (read(fd[P0_READ], &count, sizeof(count)) == sizeof(count))
printf("Parent: count = %d\n", count);
// close last descriptor
close(fd[P0_READ]);
return 0;
}
Input
./progname argOne argTwo
Output
Child: count = 12
Parent: count = 12
Edit: Single Pipe with Child Return Status
It seems from the comments of the original question your assignment may call for reaping the return status of the child process as the result count rather than returning it in a pipe. In doing so, you can do this with a single pipe-descriptor pair. I prefer the first method, but this works as well:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
// P0_WRITE - parent write target
// P1_READ - child read source
#define P1_READ 0
#define P0_WRITE 1
#define N_PIPES 2
int main(int argc, char **argv)
{
int fd[N_PIPES], count = 0;
pid_t pid;
char c;
if (pipe(fd))
{
perror("Failed to open pipe(s)");
return EXIT_FAILURE;
}
// fork child process
pid = fork();
if (pid == -1)
{
perror("Failed to fork child process");
return EXIT_FAILURE;
}
if (pid == 0)
{
// close non P1 descriptors
close(fd[P0_WRITE]);
// Return number of characters counted to parent process.
while(read(fd[P1_READ], &c, 1) == 1)
++count;
close(fd[P1_READ]);
printf("Child: count = %d\n", count);
return count;
}
// parent process. start by closing unused descriptors
close(fd[P1_READ]);
// eacn each arg entirely
for (int i=1; i<argc; ++i)
write(fd[P0_WRITE], argv[i], strlen(argv[i]));
// finished sending args
close(fd[P0_WRITE]);
// Wait for child process to return.
if (wait(&count) == -1)
{
perror("Failed to wait for child process");
return EXIT_FAILURE;
}
printf("Parent: count = %d\n", WEXITSTATUS(count));
return 0;
}
The results are the same, but note this is a biach to to debug as most debuggers will signal-trip on your child process and the real exit status is lost. On my Mac, for example, running this under Xcode trips:
Failed to wait for child process: Interrupted system call
while running from the command line gives:
Child: count = 12
Parent: count = 12
One of the many reasons I prefer the two-pipe methodology.

Defunct processes, fork()

If I run this program will I have defunct processes? I am trying to create a main program that runs 5 process in parallell and then not getting defunct processes. The trouble is mostly to be sure that this is not happening. Im not quite sure if Im doing it right this far. I have heard that it is good practice to make sure you dont have defunct processes by making your process "wait()" for as many children that has been "fork()"ed.
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void forkChildren(int nrofChildren, int *nr_of_children) {
pid_t pid;
int i;
for(i=0; i<5; i++) {
/* fork a child process */
pid = fork();
(*nr_of_children)++;
/* error occurred */
if (pid < 0) {
fprintf(stderr, "Fork failed\n");
exit(-1);
}
/* successful child */
else if (pid == 0) {
int sleeptime=1; //rand()%10;
printf("I am child: %d \nwith parent: %d \nin loop: %d \nand will sleep for: %d sec\n\n", getpid(), getppid(), i, sleeptime);
sleep(sleeptime);
printf("Ending of child: %d \nwith parent :%d in loop: %d\n\n", getpid(), getppid(), i);
}
/* parent process
else {
wait(NULL); Do I need this to make sure I dont get defunct processes???
} */
}
}
int main(int argc, char *argv[]) {
srand((unsigned int)time(NULL));
int nr_of_children=0;
if (argc < 2) {
/* if no argument run 5 childprocesses */
forkChildren(5, &nr_of_children);
} else {
forkChildren(atoi (argv[1]), &nr_of_children);
}
wait(NULL);
printf("End of %d, with %d nr of child-processes\n\n", getpid(), nr_of_children);
return 0;
}
Yes, you need to wait on the child processes. The reason is that otherwise there will still be data associated with the now zombie process, for example space for the process return value.
Have a look at using the daemon() command to place your app in the background, then use pthreads to manage the parallelism.
NAME
daemon - run in the background
SYNOPSIS
#include
int daemon(int nochdir, int noclose);
Feature Test Macro Requirements for glibc (see
feature_test_macros(7)):
daemon(): _BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)
DESCRIPTION
The daemon() function is for programs wishing to detach themselves from the controlling terminal and run in the background as
system daemons.
If nochdir is zero, daemon() changes the process’s current working directory to the root directory ("/"); otherwise,
If noclose is zero, daemon() redirects standard input, standard output and standard error to /dev/null; otherwise, no changes are made
to these file descriptors.

Blocked process in c

I am working on some code to create a process that goes blocked and then ends, I have to be able to see the blocked state with ps.
I tried with this, but my C knowledge is not good. The code doesn't print anything.
Here it is:
#include <stdio.h>
#include <stdlib.h> //exit();
#include <unistd.h> //sleep();
int main(int argc, char *argv[]) {
createblocked();
}
int pid;
int i;
int estado;
void createblocked() {
pid = fork();
switch( pid ) {
case -1: // pid -1 error ocurred
perror("error\n");
break;
case 0: // pid 0 means its the child process
sleep(); // we put the child to sleep so the parent will be blocked.
printf("child sleeping...");
break;
default: // !=0 parent process
// wait function puts parent to wait for the child
// the child is sleeping so the parent will be blocked
wait( estado );
printf("parent waiting...\n");
printf("Child terminated.\n");
break;
}
exit(0);
}
It should be easy because its only a little program that goes blocked, but I am walking in circles I think. Any advice?
sleep() takes a parameter: the number of seconds to sleep. When you omit it, it tends to return immediately.
Also wait() takes an int *, not an int.
try this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
createblocked();
}
int pid;
int i;
int estado;
void createblocked() {
pid = fork();
switch(pid)
{
case -1: // pid -1 error ocurred
perror("error\n");
break;
case 0: // pid 0 means its the child process
printf("child sleeping...\n");
sleep(500); // we put the child to sleep so the parent will be blocked.
break;
default: // !=0 parent process
// wait function puts parent to wait for the child
// thechild is sleeping so the parent will be blocked
printf("parent waiting...\n");
wait(&estado);
printf("Child terminated.\n");
break;
}
exit(0);
}
note: I also moved the printf("parent waiting...\n") above the call to wait(), so you should see it before the parent blocks waiting on the child.
edit: Also, include <unistd.h>. While not strictly required in order for the program to work (on most systems), doing so will give you better compile-time error reporting for things like missing and/or incorrectly-typed function arguments.
man sleep
man wait
You should give the number of seconds as an argument in sleep().
For wait and sleep include <unistd.h>

Resources