Two child processes create 3 child process each - linux

I'm struggling with making a C program, where the parent process creates 2 child processes, and those 2 childs create 3 child process on their own. I get the 6 child-child processes as outcome, but 2 of the 6 is the child of the parent. I can't seem to make this work.
Any help would be highly appreciated!
pid_t pid[2];
pid_t pid2[3];
for (i=0;i<2;i++) {
pid[i] = fork();
if (pid[i] == 0) {
break;
}
}
if (pid[0] != 0 && pid[1] != 0) {
// That's the father, it waits for all the childs
printf("The parent process [pid: %d, ppid: %d]\n",getpid(),getppid());
for(i=0;i<2;i++) {
wait(&tmp);
}
} else {
printf("I'm a child process [pid: %d, ppid: %d]\n",getpid(),getppid());
for (k=0; k<3; k++){
pid2[k]=fork();
if (pid2[k]==0){
break;
}
}
if (pid2[0] == 0 && pid2[1] == 0 && pid2[2] == 0){
}
else{
printf("Child of child [pid: %d, ppid: %d]\n",getpid(),getppid());
}
}

When the pid2[k] is 0 for any k, it is a grandchild.
So it only is a the first level child, when all pid2's are positive:
/* correct code */
if (pid2[0] > 0 && pid2[1] > 0 && pid2[2] > 0){
printf("I am a child with 3 children\n");
}
else{
printf("Child of child [pid: %d, ppid: %d]\n",getpid(),getppid());
}
What you wrote will happen only once for each first level child: The first grandchild k=0 will have pid2[0]==0, and will not update pid2[1] and pid2[2], these can be random or 0, depending on your compiler.
The other grand children will have the pid of their oldest brother in pid2[0].
/* incorrect code with additional printf */
if (pid2[0] == 0 && pid2[1] == 0 && pid2[2] == 0){
printf("I am one of the oldest children\n");
}
else {
printf("Child or Younger Child of child [pid: %d, ppid: %d]\n",getpid(),getppid());
}
Now you should aldo handle situations where the fork() fails (pid< 0).

Related

How can I wait for both a file-descriptor and child state change simultanously?

In Linux, one can wait on any FD using select, poll or epoll.
It is also possible to wait for child-processes to change state using wait, waitpid or waitid.
However, I can't figure a way to combine these operations, i.e., to block the calling process until either some FD becomes ready or a child process changes state.
I can use polling, by repeatedly calling non-blocking epoll then waitid, but that is wasteful.
It is possible to create a pidfd for a child process (which is accepted by epoll), but pidfd only supports waiting for child termination, while I wish to wait for any state change (specifically, for ptrace stops).
Is this not possible in Linux?
You can wait for any child status change with signalfd() and make dummy read, then get actual status with waitpid():
sigset_t mask, old_set;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, &old_set);
int sigfd = signalfd(-1, &mask, SFD_CLOEXEC);
if (sigfd == -1) {
perror("signalfd");
return 1;
}
for (int i = 0; i < 10; ++i) {
pid_t pid = fork();
if (pid == -1) {
perror("fork");
}
if (pid == 0) {
// Child process: restore blocked signals before exec() etc
sigprocmask(SIG_SETMASK, &old_set, NULL);
sleep(i % 3);
switch (i % 3) {
case 0:
raise(SIGSTOP);
break;
case 1:
raise(SIGABRT);
break;
}
exit(i);
}
printf("Spawned child %i with pid %u\n", i, pid);
}
for (;;) {
struct pollfd fds[] = {
{ .fd = STDIN_FILENO, .events = POLL_IN },
{ .fd = sigfd, .events = POLL_IN }
};
if (poll(fds, sizeof(fds)/sizeof(*fds), -1) == -1) {
perror("poll");
break;
}
if (fds[0].revents & POLL_IN) {
char buf[4096];
int ret = read(STDIN_FILENO, buf, sizeof(buf));
printf("Data from stdin: ");
fflush(stdout);
write(STDOUT_FILENO, buf, ret);
}
if (fds[1].revents & POLL_IN)
{
struct signalfd_siginfo fdsi;
read(sigfd, &fdsi, sizeof(fdsi));
for (;;) {
int status;
pid_t pid = waitpid(-1, &status, WNOHANG | WUNTRACED | WCONTINUED);
if (pid == -1) {
if (errno != ECHILD) {
perror("waitpid");
}
break;
}
if (pid == 0) {
break;
}
printf("Child %u ", pid);
if (WIFEXITED(status)) {
printf("exited with status %i\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("terminated by signal %i\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %i\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
} else {
printf("status unknown\n");
}
}
}
}
close(sigfd);

How to fork multiple processes from a same parent?

I am trying to create multiple processes from a same parent, but it always ended up with more processes than expected. I couldn't figure out how to do it and need some help here.
I found a piece of code online and tried it,
int main ()
{
pid_t pid=0;
int i=0;
for (i=0; i<3; i++)
{
pid=fork();
switch(pid)
{
case 0:
{
cout<<"\nI am a child and my pid is:"<<getpid();
cout<<endl;
exit(0);
break;
}
default:
{
cout<<"\nI am a parent and my pid is: "<<getpid();
cout<<"\nMy child pid is: "<<pid;
cout<<endl;
wait(NULL);
break;
}
}
}
return 0;
}
This code does work and creates 3 children from same parent. However, it seems like that's because after each child process was created, it was terminated immediately. So it won't fork more grandchild process in the next round of for loop. But I need to keep these child processes running for sometime and they need to communicate with the parents.
A child process may immediately break the loop to continue its work outside
int main ()
{
cout<<"\nI am a parent and my pid is: "<<getpid()<<endl;
pid_t pid;
int i;
for (i=0; i<3; i++)
{
pid=fork();
if(pid == -1)
{
cout<<"Error in fork()"<<endl;
return 1;
}
if(pid == 0)
break;
cout<<"My child "<<i<<" pid is: "<<pid<<endl;
}
if(pid == 0)
{
cout<<"I am a child "<<i<<" and my pid is "<<getpid()<<endl;
wait(NULL); // EDIT: this line is wrong!
}
else
{
cout<<"I am a parent :)"<<endl;
wait(NULL); // EDIT: this line is wrong!
}
return 0;
}
EDIT
The wait(NULL) lines are wrong. If the process has no children active, wait() has no effect, so it's useless in children here. OTOH in the parent process wait() suspends the execution until any of children exits. We have three children here, so would have to wait() three times. Additionally one can't know in advance the order of children completion, so we would need much more sophisticated code for that. Something like this:
struct WORK_DESCRIPTION {
int childpid;
// any other data - what a child has to do
} work[3];
for(i=1; i<3; i++) {
pid=fork();
...
work[i].childpid = pid;
}
if(pid == 0) // in a child
{
do_something( work[i] );
}
else
{
int childpid;
while(childpid = wait(NULL), childpid != 0)
{
// a child terminated - find out which one it was
for(i=0; i<3; i++)
if(work[i].childpid == childpid)
{
// use the i-th child results here
}
}
// wait returned 0 - no more children to wait for
}

(UNIX) How Does fork() Work in a Loop?

I have this program
childpid = 0;
int i, n;
for(i=1; i < n; i++)
if((childpid = fork())
break;
fprintf(stderr, "i:%d process ID: %ld parent ID: %ld child ID: %ld\n,
i, (long)getpid(), (long)getppid(), (long)childpid);
return 0;
It says that since a parent's process's childpid variable does not have a value of 0, it will break out of a loop. A a child process's pid is 0, and will become a parent in the next iteration.
To my knowledge, a new process is created with the code after the line fork() has been called. If a parent process breaks out of the loop as its childpid is not 0, does that not mean that the printf statement will be run once and the program will terminate since the loop has ended?
I am confused about how this program runs.
I also have this code
for(i=1; i < n; i++)
if( ((childpid = fork()) <= 0)
break;
fprintf(stderr, "i:%d process ID: %ld parent ID: %ld child ID: %ld\n,
i, (long)getpid(), (long)getppid(), (long)childpid);
return 0;
This creates a fan of processes and does the opposite of the first program. The child process breaks out of the loop since its chilpid is equal to 0, and the parent processes run in the loop.
I have an exam on Monday, and I've understood everything else
please do help :/
does that not mean that the printf statement will be run once and the program will terminate since the loop has ended?
Yes it will. But not before it has spawned a child process to carry on its legacy.
Here's a poorly drawn diagram of what's going on. In code snippet #1, the process forks itself, the parent dies, and then the child keeps going in its place.
In code snippet #2, the process forks itself, the child dies, then the parent keeps going.
In each case, the result is a long sequence of print statements.
I edited your first code a bit, and added "{ }" at the beginning and end of the if statement and for loop:
**int main()
{
int childpid = 0;
int i, n;
n=5;
for(i=1; i < n; i++){
if((childpid == fork()))
{
break;
}
fprintf(stderr, "i:%d process ID: %ld parent ID: %ld child ID: %ld\n",
i, (long)getpid(), (long)getppid(), (long)childpid);
}
wait(0);
return 0;
}**
And this was the result:
i:1 process ID: 3443 parent ID: 2790 child ID: 0
i:2 process ID: 3443 parent ID: 2790 child ID: 0
i:3 process ID: 3443 parent ID: 2790 child ID: 0
i:4 process ID: 3443 parent ID: 2790 child ID: 0
What happens is that the main process( the parent) does all the prints in the for loop, while each child process exits right after the if statement.
While on your second code, instead of
if( ((childpid = fork()) <= 0)
break;
you could write:
int f=fork();
if (f<0)
{
perror("can't create child\n");
}
if(f==0)
{
break;
}
Because if "f" is less than 0, it means that the child was not created successfully, if it was, it breaks out imediatley.

How can you make a parent process display PID of child instead of value variable?

In linux how can I make a parent process display the PID of a child process rather than the value variable?
Your chance to get the child PID is while you fork.
Python:
import os
child_pid = os.fork()
if child_pid == 0:
print "This is the child, my pid is", os.getpid()
else:
print "This is the parent, my child pid is", child_pid
C:
pid_t child_pid = fork();
if (child_pid == 0) {
printf("This is the child, my pid is %d\n", getpid());
}
else {
printf("This is the parent, my child pid is %d\n", child_pid);
}

How to run child processes concurrently

I want child processes run concurrently. Is it OK to write as to achieve this:
for(p = 0; p < N; p++){ //there will be N child processes
pidOfChild = fork();
if(pidOfChild == -1){
printf("fork() failed.\n");
exit(1);
}
else if(pidOfChild == 0){
//do sth
printf("I am a child and my PID is %d.\n", getpid());
exit(0);
}
}
It is okay, and if your parent process exits, you don't need to wait.

Resources