Related
I'm trying to send a signal around circle of processes for a certain amount of times. my first argument represents the number of processes I wish to create. my second one is just a place holder I am currently initiating to be 0. My third is the number of time I want to pass this signal around. I have designed the processes to have a relationship as such: Parent->child1,
child1->child2, child2->child3.... and so on. I'm just figuring out C and I'm confused to why my code is stopping midway. It runs for an iteration or two and then stalls out. Can someone explain why?
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int startProcess;
int N;
int numOfCycles;
sigset_t killSet;
void myHandler1 () {
if(N >= 2 && numOfCycles > 0) {
printf("N=%d, numOfCycles=%d, Signal caught. PID = %d\n",N,numOfCycles,getpid());
numOfCycles--;
kill((getpid()+1),SIGUSR1);
}
else if(N >= 2 && numOfCycles == 0) {
exit(1);
}
else if(N == 1 && numOfCycles > 0) {
printf("N=%d, numOfCycles=%d, Signal caught. PID = %d\n",N,numOfCycles,getpid());
numOfCycles--;
kill(startProcess,SIGUSR1);
}
else if(N == 1 && numOfCycles == 0) {
exit(1);
}
else {
printf("Cycle Complete\n");
exit(1);
}
}
void main(int arg, char ** argv) {
struct sigaction temp, vitas, arctic;
sigemptyset(&killSet);
sigaddset(&killSet,SIGUSR1);
N = atoi(argv[1]);
pid_t process1;
startProcess = atoi(argv[2]);
numOfCycles = atoi(argv[3]);
temp.sa_handler = myHandler1;
temp.sa_flags = SA_RESTART;
// vitas.sa_handler = myHandler2;
// vitas.sa_flags = SA_NODEFER;
//
// arctic.sa_handler = myHandler3;
// arctic.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &temp, NULL);
if (N > 1 ) {
process1 = fork();
if(process1 == 0) {
if(N > 2) {
printf("I am a child with PID=%d, PPID=%d, N =%d\n",getpid(),getppid(),N);
}
N--;
char narg = N+'0';
char *pnarg = &narg;
if(startProcess == 0) {
char nstartProcess[6];
startProcess=getppid();
sprintf(nstartProcess,"%d",startProcess);
char *pstartProcess = &nstartProcess[0];
execl("circle",argv[0],pnarg,pstartProcess,argv[3],NULL);
}
else{
if(N == 1){
printf("I am the final child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
printf("\nSignal Passing start\n\n");
kill(startProcess, SIGUSR1);
while(1) {
sigsuspend(&killSet);
}
}
else {
execl("circle",argv[0],pnarg,argv[2],argv[3],NULL);
}
}
}
else {
printf("I am a parent with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
wait(NULL);
while(1) {
sigsuspend(&killSet);
}
}
}
}
stalls out. Can someone explain why?
The final child is not woken up from sigsuspend(&killSet) because you did sigaddset(&killSet,SIGUSR1); - you seem to have thought you have to add the signal to be waited for to the set, but on the contrary the signals in the given set are blocked from delivery. So just drop the sigaddset call.
To add to #Armali and as the sigset was not the only point to consider, it's seems more simple to provide an implementation with a far more simple handler and which avoid fork+exec, you'll found explanations in the comments. I'm not sur i'have understood what is your intent, from the comments i guess that you are looking to launch N processus with the last one sending cycles time SIGUSR1 to the parent, each child processus sending SIGUSR1 to their parent on receipt. Correct me if i'm wrong.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int startProcess;
int N;
int numOfCycles;
sigset_t killSet;
// Two counters for the signal handler
int numSignals=0;
int numSignalsTotal=0;
// A simple handler that do nothing else that incrementing values in the process.
// To use a SIGINFO handler : void myHandler1 (int signal, siginfo_t *info, void *ucontext) {
void myHandler1 (int signal) {
numSignals++;
numSignalsTotal++;
}
void main(int arg, char ** argv) {
struct sigaction temp;
// As Armali pointed that, here you should not add SIGUSR1 to the sigset a you want
// to suspend your process and waiting for it.
sigemptyset(&killSet);
N = atoi(argv[1]);
pid_t process1 = 0;
startProcess = atoi(argv[2]);
numOfCycles = atoi(argv[3]);
// A more complete initialization here, you need to include SIGUSR1 here to associate it
// to your handler. It seems you doesn't need specific flag like SA_RESTART for it here,
// as the handler code doesn't require that.
temp.sa_handler = myHandler1;
sigemptyset(&temp.sa_mask);
sigaddset(&temp.sa_mask,SIGUSR1);
temp.sa_flags = 0;
temp.sa_restorer = NULL;
// Always check that your function calls return OK. Always.
if (sigaction(SIGUSR1, &temp, NULL) != 0) {
perror("ERR: Failed to set handler ...");
exit(1);
}
// Instead of a mix of fork + exec, it is more simple to keep one process and fork it for each new process.
// Here, we fork at least once, the parent process will alaways be "PARENT" and have a 0 startProcess,
// the child processes will fork themselves, the parent process is their and the new forked one will be
// the next child.
while (startProcess == 0 || N > 1 ) {
process1 = fork();
// To follow the forks : printf(" Fork pid=%d %s %s %s %s\n", process1, argv[0],argv[1],argv[2],argv[3]);
if(process1 != 0 && startProcess == 0) {
// If fork() gives us a pid and we have startProcess 0, then we are the "PARENT" process.
// The only thing we have to do is waiting for signals from our childs, if there is childs.
printf(" I am a parent with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
// If there's no child, we simply quit the loop.
if (N == 1) break;
// For reference, "PARENT" output what is its first child.
printf(" -> child = %d\n" , process1);
// Here, while we have cycles, we wait for signals
while(numOfCycles > 0) {
// If you use a handler, you need to operate synchronously with it, so here we block SIGUSR1 as we will wait for it.
if (sigprocmask(SIG_BLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to block usr1...");
exit(1);
}
// We wait for a SIGUSR1.
sigsuspend(&killSet);
// We have a SIGUSR1, we unblock SIGUSR1 as we will modify numSignals and don't want handler doing that at the same time.
if (sigprocmask(SIG_UNBLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to unblock usr1...");
exit(1);
}
// We output on STDOUT that "PARENT" caught a SIGUSR1, we should have the number of signals received in numSignals
printf(" ===> PARENT : N=%d, numOfCycles=%d, Signal caught. PID = %d, count = %d\n",N,numOfCycles,getpid(), numSignals);
// We substract that from our cycles and reset numSignals
numOfCycles-=numSignals; numSignals=0;
}
// If we are here, no more cycles, so we output on STDOUT a summary of "PARENT" processing
printf(" PARENT : N=%d, PID = %d, total = %d\n",N,getpid(), numSignalsTotal);
// Before leaving, "PARENT" should wait for its potential remaining childs to exit
printf(" PARENT waiting for child to terminate.\n");
if (wait(NULL) == -1) {
perror("ERR: PARENt failed to wait for childs termination...");
exit(1);
}
// We quit the loop, so we exit
break;
} else {
// If only one process (N=1) was asked, nothing more to do for the fork, we quit the loop then exit
if (N == 1 && startProcess == 0) break;
// We get the parent process pid in startProcess, as we are a child process
startProcess = getppid();
// If we are the forked process, we decrement N, it will "our" N as child
if (N > 1 && process1 == 0) {
N--;
}
if(process1 == 0) {
// If we are the forked process, we simply state our identity on STDOUT, the final child should be the one with N=1
if (N > 1) {
printf(" I am a child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
} else {
printf(" I am the final child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
}
if (N == 1) {
// If we are the final child, we simply have to send SIGUSR1 signals to our parent process for the number of cycles,
// after that we simply quit the loop and exit, no more forks are required.
while(numOfCycles > 0) {
printf("\n Cycle %d, first Signal start to %d\n\n", numOfCycles--, startProcess);
if (kill(startProcess, SIGUSR1) != 0) {
perror("ERR: LAST CHILD : Failed to send USR1...");
exit(1);
}
}
break;
}
// Note that if we are NOT the final child, we have to go through the loop to fork a new process for the next child.
} else {
if (N > 1) {
// If we are here, we are the forked process for a child and we are not the final child.
// So we do our payload, waiting for SIGUSR1 signals from our child and sending SIGUSR1 to our parent for the
// required number of cycles.
while(numOfCycles > 0) {
// If you use a handle, you need to operate synchronously with it, so here we block SIGUSR1 as we will wait for it.
if (sigprocmask(SIG_BLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to block usr1...");
exit(1);
}
// We wait for a SIGUSR1.
sigsuspend(&killSet);
// We have a SIGUSR1, we unblock SIGUSR1 as we will modify numSignals and don't want handler doing that at the same time.
if (sigprocmask(SIG_UNBLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to unblock usr1...");
exit(1);
}
// We output on STDOUT that this child caught a SIGUSR1, we should have the number of signals received in numSignals
printf(" ===> CHILD: N=%d, numOfCycles=%d, Signal caught. PID = %d, count = %d\n",N,numOfCycles,getpid(), numSignals);
// For each receveid signals from our child, we send one to our parent
while (numSignals > 0) {
printf("\n Signal Passing start to %d\n\n", startProcess);
if (kill(startProcess, SIGUSR1) != 0) {
perror("ERR: CHILD : Failed to send USR1...");
exit(1);
}
// We decrement accordingly our number of cycles and signals
numOfCycles--;
numSignals--;
}
}
// If we are here, no more cycles, so we output on STDOUT a summary of the child processing
printf(" CHILD : N=%d, PID = %d, total = %d\n",N,getpid(), numSignalsTotal);
// We quit the loop, so we exit, then terminate our child
break;
}
}
}
}
// We should always restore signal handler to default when we exit.
temp.sa_handler = SIG_DFL;
sigemptyset(&temp.sa_mask);
sigaddset(&temp.sa_mask,SIGUSR1);
temp.sa_flags = 0;
temp.sa_restorer = NULL;
// Always check that your function calls return OK. Always.
if (sigaction(SIGUSR1, &temp, NULL) != 0) {
perror("ERR: Failed to restore SIGUSR1 ...");
exit(1);
}
// We output on STDOUT the related PID at each process termination.
printf(" End of PID %d\n",getpid());
}
I am writing a program that can read the linux commands from a file and run them parallelly using fork() and execvp() and it works fine.
while((current = GetNextCommand(current)) != NULL){
char currentCommand[WIDTH - 1];
current->active = true;
strcpy(currentCommand, current->command);
int j=0;
int ctr=0;
char newString[LENGTH][WIDTH];
for(int i = 0; i <= strlen(currentCommand); i++){
// if space or NULL found, assign NULL into newString[ctr]
if(currentCommand[i]==' '|| currentCommand[i]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j] = currentCommand[i];
j++;
}
}
char *exe[ctr + 1];
for(int i = 0; i < ctr; i++){
exe[i] = strdup(newString[i]);
}
exe[ctr] = NULL;
t = clock();
clock_gettime(CLOCK_MONOTONIC, &start);
current->starttime = start.tv_sec;
current->PID = (pid = fork());
if(pid < 0){
fprintf(stderr, "fork Failed\n"); //output in stderr if fork fails and return
exit(1);
}
else if(pid == 0){
execvp(exe[0], exe);
//fails
exit(2);
}
}
My file is
sleep 3
ls -latr
sleep 1
pwd
sleep 1
wc /etc/passwd
sleep 10
In the parent process, I need to get the running time of each child process and rerun the command if the running time of a command is greater than 2 seconds. If the running time of a command is greater than 2, I will keep running it until the user kills the process using kill -sig pid or pkill sleep. I use a for loop and set the corresponding numbers of wait(&status). In my file, sleep 3 and sleep 10 will be greater than 2 seconds. When the process of sleep 3 has done its work, it will return to the parent and sleep 10 is still running. When I use pkill sleep now, it will be fine because sleep 10 will continue running in the parent process. However, when both of them exit from the child process and I use kill -sig pid, the whole program quit. Thus, how can I run them (sleep 3 and sleep 10) concurrently in this situation?
for(int i = 0; i < nodeIndex - 1; i++){
int status;
int pid = wait(&status);
clock_gettime(CLOCK_MONOTONIC, &finish);
CommandNode* cNode;
cNode = FindCommand(head->nextCommandPtr, pid);
elapsed = finish.tv_sec - cNode->starttime;
printf("%ld\n", elapsed);
if(elapsed < 2){
cNode->active = false;
}
else{
char rerunCommand[WIDTH - 1];
strcpy(rerunCommand, cNode->command);
int j=0;
int ctr=0;
char newString[LENGTH][WIDTH];
for(int i = 0; i <= strlen(rerunCommand); i++){
// if space or NULL found, assign NULL into newString[ctr]
if(rerunCommand[i]==' '|| rerunCommand[i]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j] = rerunCommand[i];
j++;
}
}
char *exe[ctr + 1];
for(int i = 0; i < ctr; i++){
exe[i] = strdup(newString[i]);
}
exe[ctr] = NULL;
while(elapsed > 2){
int pid2;
t = clock();
clock_gettime(CLOCK_MONOTONIC, &start);
cNode->starttime = start.tv_sec;
cNode->PID = (pid2 = fork());
if(pid2 < 0){
fprintf(stderr, "fork Failed"); //output in stderr if fork fails and return
exit(1);
}
else if(pid2 == 0){
printf("What happened here.\n");
execvp(exe[0], exe);
exit(2);
}
else{
wait(&status);
clock_gettime(CLOCK_MONOTONIC, &finish);
elapsed = finish.tv_sec - cNode->starttime;
if(elapsed > 2) {
printf("What is this: %d %d\n", pid2, cNode->PID);
}
}
}
}
}
regarding the question in the title:
Yes you can, just loop until the returned value is -1
Yes, indeed this is a correct way of ensure that all your children have finished before you continue:
pid_t pid;
...
while((pid = wait(NULL)) >= 0)
printf("child pid=%d ended.\n", pid); /* or whatever you want */
/* no more children active after this point, you don't need
* to check the value of errno, except if you allow this
* process to be interrupted by a signal. */
This is the old legacy of the zombie processes (like a title for a walking dead movie): A zombie process is a process that has exit(2)ed and which parent has not wait(2)ed for. It has all its resources freed, except its process table entry (in which its exit code and accounting records are stored). In this way, when the parent does a wait(2) system call, the kernel can navigate the table of its children processes and check if it has to return an error (if the list is empty), or there's some child that has ended and can return its exit(2) code to the parent. You can only use wait(2) properly (e.g. without errors) if you have previously made a fork(2), and wait(2) signals an error in case you have created no child processes.
To get the running time of the children, you need to use one of the alternate syscalls to wait(2) (wait3(2) or wait4(2), as per FreeBSD manual page, on linux there are similar syscalls)
Try this simple example:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define N 7
#define PARENT_SLEEP 30
#define CHILD_MAXSLEEP 60
int main()
{
int i;
pid_t mypid = getpid();
for(i = 0; i < N; i++) {
pid_t chpid = fork();
switch (chpid) {
case -1: /* error */
fprintf(stderr,
"Parent [pid=%d]: fork: %s\n",
mypid,
strerror(errno));
goto out; /* we want to break the loop */
case 0: /* child */
/* reinit mypid to reflect proper value */
mypid = getpid();
printf("Child [pid=%d]: start\n", mypid);
/* we initialize random module after fork, so
* all children don't get the same random
* sequence. Probably all of them will take
* the same value for the time, so we use also
* the pid for the seed to be different for
* each child. */
srandom( mypid ^ time(NULL) );
/* a random time between 1 and CHILD_MAXSLEEP */
int myrandom = random() % CHILD_MAXSLEEP + 1;
printf("Child [pid=%d]: wait for %d secs.\n",
mypid, myrandom);
sleep( myrandom );
printf("Child [pid=%d]: exiting with code=%d\n",
mypid, myrandom);
exit( myrandom );
default: /* parent */
printf("Parent[pid=%d]: I have started"
" child (pid = %d)\n", mypid, chpid);
break;
} /* switch */
} /* for */
out:
/* if you put a delay here, before doing wait()s,
* and you execute a ps(1) command before the parent
* begins to make waits, and some of the children have
* already died, you'll see the zombie processes
* (they are marked with a Z in status) */
printf("Parent [pid=%d]: sleeping for %ds.\n",
mypid, PARENT_SLEEP);
sleep(PARENT_SLEEP);
printf("Parent [pid=%d]: beginning to wait.\n",
mypid);
int status;
pid_t child;
while ((child = wait(&status)) >= 0) {
printf("Parent[pid=%d]: "
"detected exit(%d) from "
"child(pid=%d)\n",
mypid,
WEXITSTATUS(status),
child);
}
printf("Parent[pid=%d]: exiting\n", mypid);
exit(0);
} /* main */
and one example of one execution:
$ a.out
Parent[pid=81452]: I have started child (pid = 81453)
Parent[pid=81452]: I have started child (pid = 81454)
Parent[pid=81452]: I have started child (pid = 81455)
Parent[pid=81452]: I have started child (pid = 81456)
Child [pid=81453]: start
Child [pid=81453]: wait for 34 secs.
Child [pid=81455]: start
Child [pid=81455]: wait for 56 secs.
Child [pid=81456]: start
Child [pid=81456]: wait for 42 secs.
Parent[pid=81452]: I have started child (pid = 81457)
Parent[pid=81452]: I have started child (pid = 81458)
Parent[pid=81452]: I have started child (pid = 81459)
Parent [pid=81452]: sleeping for 30s.
Child [pid=81454]: start
Child [pid=81454]: wait for 9 secs.
Child [pid=81457]: start
Child [pid=81457]: wait for 58 secs.
Child [pid=81458]: start
Child [pid=81458]: wait for 30 secs.
Child [pid=81459]: start
Child [pid=81459]: wait for 14 secs.
Child [pid=81454]: exiting with code=9
Child [pid=81459]: exiting with code=14
Child [pid=81458]: exiting with code=30
Parent [pid=81452]: beginning to wait. <<<<< before this message, you can see Zombie processes.
Parent[pid=81452]: detected exit(14) from child(pid=81459)
Parent[pid=81452]: detected exit(30) from child(pid=81458)
Parent[pid=81452]: detected exit(9) from child(pid=81454)
Child [pid=81453]: exiting with code=34
Parent[pid=81452]: detected exit(34) from child(pid=81453)
Child [pid=81456]: exiting with code=42
Parent[pid=81452]: detected exit(42) from child(pid=81456)
Child [pid=81455]: exiting with code=56
Parent[pid=81452]: detected exit(56) from child(pid=81455)
Child [pid=81457]: exiting with code=58
Parent[pid=81452]: detected exit(58) from child(pid=81457)
Parent[pid=81452]: exiting
$ _
While I was playing with C, and trying to learn more about processes, forks and wait, I've reached a problem where I'm not able to wait for a sibling process to finish until I can continue.
So, here's the problem:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdlib.h>
int processoDisplayLyric;
int processoDisplayGraph;
int processoTimer;
int main(){
int numeroMusicaAtual = 0;
int continueWorking = 0;
int fathersPID = getpid();
while(continueWorking == 0) {
//Create graph process
processoDisplayGraph = fork();
if(processoDisplayGraph == 0){
int work = 0;
while(work == 0){
pause();
}
}
if(processoDisplayGraph != 0){
//Create lyric process.
processoDisplayLyric = fork();
if(processoDisplayLyric == 0){
int work = 0;
while(work == 0){
pause();
}
}
}
if(processoDisplayLyric != 0 && processoDisplayGraph != 0){
//Create timer process.
processoTimer = fork();
if(processoTimer == 0){
printf("I was created and i just want to wait for my brothers.\n");
}
}
if(getpid() != fathersPID){
wait(processoDisplayLyric);
wait(processoDisplayGraph);
}else{
//It's the father.
int child_status;
for (int i = 0; i < 2; i++) {
pid_t wpid = waitpid(processoDisplayLyric, &child_status, 0);
if (WIFEXITED(child_status))
printf("Saw %d done with %d\n", wpid, WEXITSTATUS(child_status));
else
printf("Child %d terminated abnormally\n", wpid);
}
}
numeroMusicaAtual++;
}
}
The thing is: processDisplayLyric, processDisplayGraph and processTimer are created, BUT, the Timer DOESN'T wait for the other two to finish (something that should never happen!!!).
Under standard POSIX, only a parent process can wait for its (immediate) children to die.
Sibling processes cannot wait for other sibling processes to die.
Child processes cannot wait for parent processes to die.
A grandparent process cannot wait for grandchildren to die.
There are ways to detect whether a parent process is dead (the result of getppid() is 1, or if you recorded the original PPID, then signalling it fails). You can find out if you could signal a known PID — and if it doesn't exist, you can't. There may be some alternatives on some platforms using other APIs. But there's no general analogy to wait() for siblings or parents (or any other related process) — only children can be waited for.
Note that recent versions of Linux (since kernel 3.4) have the prctl() system call. The PR_SET_CHILD_SUBREAPER option allows a process other than the system process (PID 1 usually) to collect the status information of dead children in its process hierarchy. That's still not collecting sibling processes; it is only able to collect children, grandchildren, great-grandchildren, and so on.
I need to create a program that creates n number of processes and displays information. When each process ends, I am to print it's PID and the exit status. The way I am doing it, the parent program waits to create the next process until the current one ends. I need it so that it keeps creating the child processes and just displays the exit information when ever one process ends without blocking the parent from continuing. I can;t figure out where to put my wait to ensure this. Below is my code:
int main (int argc, char *argv[])
{
if (argc < 2)
{
printf("\n\nUsage: %s <enter a number (12 or less)>\n\n", argv[0]);
exit (-1);
}
else
{
int *processNum = (int *)malloc(sizeof(12));
int processNumTemp;
processNumTemp = atoi(argv[1]);
processNum = &processNumTemp;
if(*processNum > 12 || *processNum < 1)
{
printf("\n\nUsage: %s <enter a number (12 or lrss)>\n\n", argv[0]);
}
else
{
parentInfo(processNum);
createChildProcess(processNum);
}
}
return 0;
}
//Name: parentInfo
//Description: Displays information about the parent process
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void parentInfo(int *processNum)
{
printf("Parent process ID: %d\n", getppid());
printf("Number of processes to create: %d\n", *processNum);
}
//Name: createChildProcess
//Description: Creates n number of child processes.
// For each child process, it says its a child process and it
// displays its PID.
// After each child process closes, the parent displays info.
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void createChildProcess(int *processNum)
{
int i;
int childStatus;
pid_t childpid;
/*The for loop will create n number of processes based on the value of processNum.*/
for(i = 1; i <= *processNum; i++)
childpid = fork();
//Executes if fork didn't work
if(childpid < 0)
{
perror("fork");
exit(1);
}
//Executes if the fork worked
else if( childpid == 0)
{
int pid = getpid();
//Prints a message and the child processe's PID
printf("\nHello I am a child process.\n");
printf("My PID is %d. \n", getpid());
for(int x = 1; x <= pid; x ++);
exit(15);
}
}
//Executes after the child process has ended
//Checks the child process's exit status
waitpid(childpid, &childStatus, WUNTRACED);
printf("\nPID of the child process that was just created: %d.\n", childpid);
if(WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else if(WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else if(WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
Before fork code
signal(SIGCHLD, childHandler);
In childHandler put your waitpid code.
void childHandler(int signum)
{
pid_t childpid;
int childstatus;
while ((childpid = waitpid( -1, &childstatus, WNOHANG)) > 0)
{
if (WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else
if (WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else
if (WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
}
}
You should not use async-unsafe calls like printf inside a signal handler so alter your code to save the status in a global or heap allocated array - you know the size to create from processNum - and print the status info outside the handler.
Also, as currently structured, your parent could end before reaping all the children. Add a counter for the children so that you wait on all of them before the parent exits.
Look into signal SIGCHLD. If you have it blocked, you must unblock it or might instead explicitly check for it.
The purpose of wait is to, well, wait, so the way to solve your problem is to first create all the children, then start waiting for them to terminate.
Here is a program which does that:
// fork
#include <unistd.h>
// wait
#include <sys/types.h>
#include <sys/wait.h>
// exit
#include <stdlib.h>
//printf
#include <stdio.h>
void child( int id)
{
int seed= id;
int x= rand_r( &seed) % 10;
sleep( x);
exit( x);
}
int main( int argc, char *argv[])
{
const int n= 5;
int i;
printf( "creating %d children.\n", n);
for ( i= 0; i < n; ++i) {
pid_t pid= fork();
if ( !pid)
child( i); // does not return
else
printf( "child [0x%x] created.\n", pid);
}
// all the children are created now
// now we wait for them to terminate
printf( "waiting for children to terminate.\n", n);
for ( i= 0; i < n; ++i) {
int result;
pid_t pid= wait( &result);
printf( "child [0x%x] terminated with result [%u].\n", pid, WEXITSTATUS( result));
}
puts( "all children terminated.");
}
I know I'm going to need to use fork(), but this just creates a single child process. Do i simply call fork again from within the child process? Also, I need them to communicate through a signal or pipe, which is easier to implement and what do i need to know for doing that (functions, etc..)
To create a second process, call fork() again - either within the parent or the child (but not both!). Which you choose depends on whether you want this process to be a child of the original parent or a child of the first child process (it is usual for it to be a child of the original parent).
Communicating through a pipe is much simpler and more reliable than using signals. pipe(), close(), read(), write() and select() are the key functions here.
For example, to have the parent create two child processes, you would do something like:
pid_t child_a, child_b;
child_a = fork();
if (child_a == 0) {
/* Child A code */
} else {
child_b = fork();
if (child_b == 0) {
/* Child B code */
} else {
/* Parent Code */
}
}
Another fancy code using && operator:
pid_t c1_pid, c2_pid;
(c1_pid = fork()) && (c2_pid = fork()); // Creates two children
if (c1_pid == 0) {
/* Child 1 code goes here */
} else if (c2_pid == 0) {
/* Child 2 code goes here */
} else {
/* Parent code goes here */
}
#include <stdio.h>
#include <unistd.h>
void main(){
int pi_d ;
int pid ;
pi_d = fork();
if(pi_d == 0){
printf("Child Process B:\npid :%d\nppid:%d\n",getpid(),getppid());
}
if(pi_d > 0){
pid = fork();
if(pid > 0){
printf("\nParent Process:\npid:%d\nppid :%d\n",getpid(),getppid());
}
else if(pid == 0){
printf("Child Process A:\npid :%d\nppid:%d\n",getpid(),getppid());
}
}
}
output :
Parent Process:
pid:3648
ppid :2379
Child Process B:
pid :3649
ppid:3648
Child Process A:
pid :3650
ppid:3648
You can put the fork in a loop and generate as many child processes as you need.
I did that on a project recently.
for(nSon=0; nSon < nSonsAsked; nSon++) {
Log_Print("Setup son #%.2u ", nSon+1);
if((pid = fork()) == 0) {
/* Do child stuff init, like connect the pipes, close shared handles */
return iTMInChild(...); /* A specific function of the child work */
/* The life of the child should not go beyond that point, i.e. the loop is over
or else the child will spawn even more processes. */
}
else if(pid > 0) {
/* Father process stuff. Here I initialise an array with the pid of the forked */
/* processes, this way I can index with the number of processes.*/
pid[nSon] = pid;
}
else
return Err_Print(ERR_FORK_FAILED, "fork failed. errno=%d \"%s\"\n", errno, strerror(errno));
}
Log_Print() and Err_Print() are internal functions but quite obvious so I let them like they are.
There is one aspect with the variables that has to be explained. nSon and nSonAsked should be declared as globals not as stack variables. This way, their value persists in the forked process. This means that the nSon variable will have a different value in each of the children. This allows it to have a simpler numbering scheme than the ownpid() number.
To get it completely right, there are a lot of details to get right. You will have to set signal handlers in the father process to detect the death of a child, likewise the other way round (only possible on Linux, other Unix (at least Solaris) do not support parent death signals).
You have to be aware that open file descriptors in the father process will be also open in the child after fork and it will be the same one. This opens a lot of concurrency problems if you're not aware of it (the solution is using dup() and close() in the right places).
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
system ("clear");
int i ;
pid_t childa,childb,childa1,childa2,childb1,childb2;
printf("\n \t \t I am the parent process with ID %d \n",getpid());
childa=fork();
if (childa == 0 )
{
printf("\nI am a child A with PID %d and my parent ID is %d\n",getpid(),getppid());
}
else
{
childb = fork();
if (childb == 0)
{
printf("\nI am Child B with ID %d and my parent ID is %d\n",getpid(),getppid());
}
else
{
sleep(1);
}
}
}
In this example they are just sleeping for a few random sec. It also has all the pid, so we can send SIGNAL to communicate... Most of the #includes are commented cause they were useless where I compiled.
#include <stdlib.h> // exit() ...
#include <stdio.h> // printf() ...
// Compile with -lrt -> cc file_name.c -lrt
//#include <fcntl.h>
//#include <sys/stat.h>
//#include <sys/types.h>
//#include <sys/wait.h> // may need this for wait()
//#include <time.h>
//#include <unistd.h> // and this one for fork()
// In the start function you can do whatever you want.
void start (const int azon) {
// For children processes
srand( time(NULL) );
unsigned t = rand()%5; // printf("%d\n", t);
sleep(t);
printf("%d. process reached the end.\n", azon);
exit(0);
}
int main() {
const int N = 5;
pid_t pids[N];
int i;
// The 'for' loop make 'N' process with 'fork()'.
// The children processes will call the start function.
// Since after fork() you will get 2 process. One Parent, and One Child
// The returning value from fork() is saved in "pids" which is an
// integer AND it is (<0) IF something went wrong.
// it is (>0) IF 'we are' in the Parent process,
// because this number is the Child process' ID (pid).
// and Last it is (==0) IF 'we are' in the Child process.
for (i = 0; i < N; i++) {
pids[i] = fork();
sleep(1);
if (pids[i] == 0) start(i+1); // ... OR you can make a switch(..)
}
// This 'for' loop in the wait(NULL) statement ONLY move on when a
// process ended, so it waits until 'N' proc ends.
for (i = 0; i < N; i++)
wait(NULL);
printf("Partent process reached the end\n");
return 0;
}
Just a little contribution, if you want to create 2 childs from the same parent you could use this code below. In which one father create 2 child processes (lazy and active).
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main (){
pid_t lazy_child;
lazy_child = fork();
if(lazy_child == 0){ // This is the lazy child process.
printf("LAZY CHILD:%d\n", getpid());
}
else if(lazy_child > 0){ // This is the father process.
pid_t active_child = fork();
if(active_child == 0){ // This is the active child process.
printf("ACTIVE CHILD:%d\n", getpid());
}
else if(active_child > 0){ // This is the father process.
printf("FATHER:%d\n", getpid());
}
else{ // Fork doesnt work.
printf("fork error\n");
exit(1);
}
}
else{ // Fork doesnt work.
printf("fork error\n");
exit(1);
}
return 0;
}
If you run this code, you should get a similar output:
$ ./a.out
FATHER:14501
ACTIVE CHILD:14503
LAZY CHILD:14502
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t AliceID, BobID;
double n=0;
int i1 =0;
/* fork a child process */
AliceID = fork();
if (AliceID < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (AliceID == 0) { /* child Alice code */
for(int i=1; i<11; i++)
{n = n+i;
i1++; }
double avg1 = n/i1;
printf("From Alice: the average of 1,2, …, 10 is the-average-she-calculated");
printf(" sum = %.2f and avg = %.2f \n",n, avg1);
}
else {
BobID = fork();
if (BobID == 0) { /* Child Bob code */
printf("From Bob: I am born to print this and then die.\n");
} else { /* Parent Code */
/* parent will wait for the child to complete */
wait(NULL);
printf("From parent: AliceID is %d \n", AliceID);
printf("From parent: Bob is %d \n", BobID);
printf("Parent ID %d \n", getpid());
}
}
return 0;
}