How to run child processes concurrently - linux

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.

Related

How can I print a message from a signal handler

I have small project for practice in system calls. The idea is to create a Rock paper scissors game. The controller need to create two child processes and when two processes are created they are supposed to send ready command to the controller (parent process) using SIGUSR1 signal. I have created the two children processes and the signal sent the signal to the controller but the problem message does not print out. what am I wrong?
Here is my code.
#include<stdio.h>
#include<unistd.h> // fork(); for creating processes and pipe()s
#include<signal.h>
#include<sys/signal.h>
#include<stdlib.h>
void handle_sigusr1(int sig){
printf("Sending ready command...\n");
}
int x = 0;
int main(int args, char* argv[]){
int player0, player1;
player0 = fork();
if(player0 != 0){
player1 = fork();
}
if( player0 == 0){
kill(getppid(), SIGUSR1);
sleep(2);
}else if(player1 == 0){
sleep(3);
kill(getppid(), SIGUSR1);
}else{
wait(NULL);
struct sigaction sa = { 0 };
sa.sa_flags = SA_RESTART;
sa.sa_handler = &handle_sigusr1;
sigaction(SIGUSR1, &sa, NULL);
if(signal(SIGUSR1, handle_sigusr1)){
x++;
printf("Controller: Received ready command. Total %d\n", x);
}
}
return 0;
}
In your code, there are 2 major issues to modify.
First of all, move the signal handler above the wait() function, otherwise you are defining how to handle the signal after receiving it
signal(SIGUSR1, handle_sigusr1);
wait();
Then, the parent process is waiting for only 1 child to receive the signal. You should add a loop to wait both the child processes in the parent statement branch

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);

Two child processes create 3 child process each

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).

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
}

second call prctl() dont work

I try write program, which realize next idea:
After start, program using fork() and:
parent process stopped on function wait() (for waiting death child process);
child process use prctl(PR_SET_PDEATHSIG, SIGHUP), and setup signal handler (It's helps detect parent death);
After death any process, program use fork() again.
void forking_process() {
pid_t id;
printf("forking_process is called!\n");
if (id = fork()) {
parent_process_operation();
} else {
child_process_operation();
}
}
void parent_process_operation() {
int status = 0;
printf("It's parent process! Pid = %d\n", (int)getpid());
pid_t chid = wait(&status);
printf("Terminated child process with PID = %d\n", chid);
inform_about_parent_death(status);
}
void child_process_operation() {
printf("It's child process! pid = %d, ppid = %d\n",
(int)getpid(), (int)getppid());
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = inform_about_parent_death;
if (sigaction(SIGHUP, &sa, NULL))
fprintf(stderr, "sigaction error\n");
prctl(PR_SET_PDEATHSIG, SIGHUP);
while(1) {
printf("."); fflush(stdout);
sleep(1);
}
}
void inform_about_parent_death(int i) {
printf("Process is dead. Restart!\n");
forking_process();
}
int main (void) {
forking_process();
return EXIT_SUCCESS;
}
If I run this application, and in another terminal kill child process - then will create child process.
If I kill the parent process once, - signal handler started and call fork().
If I again kill the parent process, - signal handler not responded.
That is - prctl() in first process work, but prctl() in second child process don't work.
Why it is happen? How I can correct it's program?

Resources