I made some headway on my program by allowing it to run for a random number of time between 0 and 20 using rand()%20. However, I cannot figure out how to fork() off multiple processes, 2 maximum.
If I understand fork() correctly, I have created 1 parent and 1 child process in my program. The rand1 value in
else if (pid==0) {
mypid = getpid();
cout << "Child pid is " << mypid << "\n";
execlp("./idle","./idle","1",rand1,0); }
in execlp will create and run the ./idle processes for whatever was generated, correct? For example if rand1 == 19, each process, parent and child, will run for 19 seconds before the program finishes, not including the sleep() timers in the code.
Now my main problem is forking two processes so that I'm not simply left with 1 parent and 1 child, but rather 2 parents and 2 children, but running through the program as it currently works.
I'm lost and hopefully some guidance can come from this post's future replies.
Thank you!
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <time.h>
using namespace std;
using std::cout;
volatile sig_atomic_t keep_going = 2;
void catch_child (int sig)
{ int status, p;
p = waitpid(-1,&status,WNOHANG);
if (p==0) return;
keep_going=0;
cout<<"Child process caught: "<< p <<endl;
return;
}
int main()
{
pid_t pid;
pid_t mypid;
int rand1;
int i;
srand(time(NULL)); //init seed
rand1 = rand()%20; //generates random number 0 - 20
cout << "This is the random number (rand1): " << rand1 << "\n"; //output to see how long
signal (SIGCHLD, catch_child); //when child is sent, run function catch_child
pid = fork();
if (pid<0) {
cout<<"Error\n";
return 0;
}
else if (pid==0) {
mypid = getpid();
cout << "Child pid is " << mypid << "\n";
execlp("./idle","./idle","1",rand1,0);
} else {
mypid=getpid();
cout<<"Parent procss is " << mypid << " and child is " << pid << "\n";
sleep(3);
cout<<"Pausing child " << pid <<" for " << rand1 << " seconds\n";
kill(pid,SIGSTOP);
for (int i=0; i < rand1; i++) sleep(3);
cout<<"Resuming child "<<pid<<"\n";
kill(pid,SIGCONT);
cout<<"Parent process pid is "<<mypid<<" waiting for child to stop\n";
while (keep_going==rand1) sleep(2);
cout <<"Parent knows that Child now done\n";
}
return 0;
} //keep
UPDATE:
Here's a sample run of what appears to be a semi working program. Attached is the code and an image regarding the sample run with the updated code below.
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <time.h>
using namespace std;
using std::cout;
volatile sig_atomic_t keep_going = 2;
void catch_child (int sig)
{ int status, p;
p = waitpid(-1,&status,WNOHANG);
if (p==0) return;
keep_going=0;
cout<<"Child process caught: "<< p <<endl;
return;
}
int main()
{
pid_t pid;
pid_t mypid;
int rand1;
int i;
srand(time(NULL)); //init seed
rand1 = rand()%20; //generates random number 0 - 20
cout << "This is the random number (rand1): " << rand1 << "\n"; //output to see how long
signal (SIGCHLD, catch_child); //when child is sent, run function catch_child
;
for(int i=0;i<2;i++){
pid = fork();
if (pid<0) {
cout<<"Error\n";
return 0;
}
else if (pid==0) {
mypid = getpid();
cout << "Child pid is " << mypid << "\n";
execlp("./idle","./idle","1",rand1,0); //does rand1 make the processes run for rand1's value?
} else {
mypid=getpid();
cout<<"Parent procss is " << mypid << " and child is " << pid << "\n";
sleep(3);
cout<<"Pausing child " << pid <<" for " << rand1 << " seconds\n";
kill(pid,SIGSTOP); //SIGSTOP acts as a PAUSE
for (int i=0; i < rand1; i++) sleep(3);
cout<<"Resuming child " << pid << "\n";
kill(pid,SIGCONT);
cout<<"Parent process pid is "<<mypid<<" waiting for child to stop\n";
while (keep_going==rand1) sleep(2);
cout <<"Parent knows that Child now done\n";
}
}
return 0;
}
Related
The program I am working on is called myfile - It should find a file in a certain searchpath. You should also be able to search for multiple files and if so, I MUST create multiple child processes with fork(). The problem is, i dont get the expected outcome printed out. If I am searching for multiple files, only the first file gets "returned". I think it has something todo with the second for in the else statement. For debugging I am printing out every PID of the child processes. Is the problem maybe that the child processes are working with the same variables at the same time?
The Code:
`
#include<iostream>
#include<dirent.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
using namespace std;
int main(int argc, char** argv)
{
struct dirent *d;
DIR *dr;
dr = opendir(argv[1]);
pid_t pid;
int numberOfFiles = argc - 2;
if(dr!=NULL){
if(numberOfFiles == 1){
// normal search without fork
for(d=readdir(dr); d!=NULL; d=readdir(dr)){
if(strcmp(d->d_name, argv[argc-1]) == 0){
cout << "<" << getpid() << ">: " << argv[argc-1] << ": <" << realpath(argv[argc-1], NULL) << ">" <<endl;
}
}
}else{
// search with fork
for(int i = 2; i < argc; i++){
if(fork() == 0){
cout << "Current PID: " << getpid() << " " << argv[i] <<endl;
for(d=readdir(dr); d!=NULL; d=readdir(dr)){
if(strcmp(d->d_name, argv[i]) == 0){
cout << "Current i=" << i << " "<< "<" << getpid() << ">: " << argv[i] << ": <" << realpath(argv[i], NULL) << ">" <<endl;
}
}
exit(0);
}
}
for(int i=0; i < numberOfFiles; i++){
wait(NULL);
}
}
}else
cout<<"\nError Occurred!"<<endl;
cout<<endl;
return 0;
}
`
Screenshot of output in terminal:
The problem is, i dont get the expected outcome printed out. If I am searching for multiple files, only the first file gets "returned". I think it has something todo with the second for in the else statement. For debugging I am printing out every PID of the child processes. Is the problem maybe that the child processes are working with the same variables at the same time?
Looks like a problem with opendir, readdir, and reusing variables. I cut your program down to:
int main(int argc, char **argv)
{
struct dirent *d;
DIR *dr;
dr = opendir(argv[1]);
for (int i = 2; i < argc; i++)
{
if (fork() == 0)
{
cout << "Current PID: " << getpid() << " " << argv[i] << endl;
for (d = readdir(dr); d != NULL; d = readdir(dr))
{
cout << getpid() << "\t" << d->d_name << endl;
}
exit(0);
}
}
for (int i = 0; i < argc - 2; i++)
wait(NULL);
}
And got this output (from ./testfork ../bla 1 2):
Current PID: 17197 1
Current PID: 17198 2
17198 test.txt
17198 ..
17198 .
Which shows that once one process has read to end with readdir, then the other gets nothing. However, if I move the call to opendir to after the fork:
int main(int argc, char **argv)
{
struct dirent *d;
DIR *dr;
for (int i = 2; i < argc; i++)
{
if (fork() == 0)
{
dr = opendir(argv[1]); // <- Here
cout << "Current PID: " << getpid() << " " << argv[i] << endl;
for (d = readdir(dr); d != NULL; d = readdir(dr))
{
cout << getpid() << "\t" << d->d_name << endl;
}
exit(0);
}
}
for (int i = 0; i < argc - 2; i++)
wait(NULL);
}
The the output becomes:
Current PID: 17751 1
17751 test.txt
17751 ..
17751 .
Current PID: 17752 2
17752 test.txt
17752 ..
17752 .
I don't quite understand why this happens, since the way fork works should ensure that each process get their own copy of the memory (though possibly only after writing to it). So when one process modifies dr, then that change should not be reflected in the other processes.
Perhaps it is due to dr actually being changed through system calls (by way of readdir), and not by the process directly?
In the below program i'm trying to implement these conditions:
I'm trying to only implement the first child process to print “hi”?
and the root process to print “areyou”?
and the final child process must exit from the system without doing anything?
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
pid_t pid1,pid2,pid3,pid4;
int function(){
pid1=fork();
if(pid1>0)
{
cout << "hi" << getpid()<<" " << getppid()<< endl; /*first child process should print "hi"*/
}
pid2=fork();
cout << "hell" << getpid()<<" " << getppid()<< endl;
pid3=fork();
cout << "how " <<getpid() <<" "<<getppid() <<endl;
pid4=fork();
if(pid4>0){
return 0;/* final child process should exit from the system with out doing anything*/
}
else{
cout << "areyou "<<getpid()<<" "<<getppid()<<endl;
}
}
int main() {
/* and the root process should print "are you"*/
function();
}
-with if(pid1>0) i guess i tried to implement first child to output "hi" and i feel i'm lost in understanding how can i get only the root parent process to print "areyou", and how to control the last child to exit with out doing anything
You may do something like
void function()
{
pid_t pid1, pid2, pid3, pid4;
pid1 = fork();
if (pid1 == 0)
{
// first child process should print "hi"
cout << "hi " << getpid() << " " << getppid()<< endl;
}
pid2 = fork();
cout << "hell " << getpid() <<" " << getppid() << endl;
pid3 = fork();
cout << "how " << getpid() <<" "<<getppid() << endl;
pid4 = fork(); // Mostly useless as only parent print something for this one
if (pid1 == 0 && pid2 == 0 && pid3 == 0 && pid4 == 0){
return; // final child process should exit from the system with out doing anything
} else if (pid1 > 0 && pid2 > 0 && pid3 > 0 && pid4 > 0){
cout << "areyou "<< getpid() << " "<< getppid() << endl;
}
}
Demo
with if(pid1>0) i guess i tried to implement first child to output "hi"
No, it's the parent that gets a positive pid (on success), because it gets the process-id of the child it just forked, or -1 if the fork call fails. The child receives a return value of 0.
What you want to do goes like this:
if(pid1 < 0)
{
cout << "fork failed to create a child process."
}
else if (pid1 > 0) // Parent
{
cout << "areyou";
}
else // child
{
cout << "hi";
}
Modify the following program so that the child process creates another child and wait for it. The grand child prints out the id's of itself, its parent and grandparent.
This is what ive tried so far...
//testWait.cpp
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main()
{
pid_t pid; //process id
string message;
int n;
int exit_code;
cout << "fork program starting\n";
pid = fork();
switch ( pid )
{
case -1:
cout << "Fork failure!\n";
return 1;
case 0:
message = "This is the child\n";
n = 5;
exit_code = 9;
break;
default:
message = "This is the parent\n";
n = 3;
exit_code = 0;
break;
}
for ( int i = 0; i < n; ++i )
{
cout << message;
sleep ( 2 );
}
//waiting for child to finish
if ( pid > 0 ) //parent
{
int stat_val;
pid_t child_pid;
child_pid = wait ( &stat_val ); //wait for child
cout << "Child finished: PID = " << child_pid << endl;
if ( WIFEXITED ( stat_val ) ) //rerturn true if child terminated normally that is by exit(3)
cout << "child exited with code " << WEXITSTATUS ( stat_val ) << endl; //returns the exit status of the child.
else
cout << "child terminated abnormally!" << endl;
}
/*
if(pid == 0) //child
{
int stat_val;
pid_t gc_pid, pid2;
pid2 = fork();
//gc_pid = fork();
gc_pid = wait ( &stat_val ); //wait for grandchild
if(pid2 == 0)
{
cout << "This is the GrandChild\n";
exit_code = 9;
cout << "GrandChild finished: PID = " << gc_pid << endl;
//cout << "My parent is PID = " << pid;
}
//cout << "GrandChild finished: PID = " << gc_pid << endl;
}
*/
exit ( exit_code );
}
The part of code where i commented out is what ive attempted.
if(pid == 0) //child
{
int stat_val;
pid_t gc_pid, pid2;
pid2 = fork();
//gc_pid = fork();
gc_pid = wait ( &stat_val ); //wait for grandchild
if(pid2 == 0)
{
cout << "This is the GrandChild\n";
exit_code = 9;
cout << "GrandChild finished: PID = " << getpid() << endl;
cout << "My parent is PID = " << getppid()<< endl;
}
cout << "GrandChild finished: PID = " << getpid() << endl;
}
I have a program that creates new processes "one by one". Is it possible to change this code so it creates a "list" of processes – i.e. child 1 being the parent of child 2, child 2 being the parent of child 3, etc.?
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "err.h"
using namespace std;
int main ()
{
pid_t pid;
int i;
cout << "My process id = " << getpid() << endl;
for (i = 1; i <= 4; i++)
switch ( pid = fork() ) {
case -1:
syserr("Error in fork");
case 0:
cout << "Child process: My process id = " << getpid() << endl;
cout << "Child process: Value returned by fork() = " << pid << endl;
return 0;
default:
cout << "Parent process. My process id = " << getpid() << endl;
cout << "Parent process. Value returned by fork() = " << pid << endl;
if (wait(NULL) == -1)
syserr("Error in wait");
}
return 0;
}
If you want to keep the loop in order to dynamically set the depth of the fork tree,
// Set DEPTH to desired value
#define DEPTH 4
int main ()
{
pid_t pid;
int i;
cout << "My process id = " << getpid() << endl;
for (i=1 ; i <= DEPTH ; i++) {
pid = fork(); // Fork
if ( pid ) {
break; // Don't give the parent a chance to fork again
}
cout << "Child #" << getpid() << endl; // Child can keep going and fork once
}
wait(NULL); // Don't let a parent ending first end the tree below
return 0;
}
Output
My process id = 6596
Child #6597
Child #6598
Child #6599
Child #6600
Use fork in a set of nested ifs
#include<stdio.h>
int main()
{
printf("Parent PID %d\n",getpid());
if(fork()==0)
{
printf("child 1 \n");
if(fork()==0)
{
printf("child 2 \n");
if(fork()==0)
printf("child 3 \n");
}
}
return 0;
}
Output
Parent PID 3857
child 1
child 2
child 3
For n processes,
#include<stdio.h>
void spawn(int n)
{
if(n)
{
if(fork()==0)
{
if(n)
{
printf("Child %d \n",n);
spawn(n-1);
}
else
return;
}
}
}
int main()
{
printf("Parent PID %d\n",getpid());
int i=0;
spawn(5);
return 0;
}
int make_proc(int counter, int parent){
pid_t x=getpid();
std::cout << counter << " process "<< x << " : parent" << parent<< std::endl;
if (counter==0) {
return 1;
}
else {
counter=counter-1;
pid_t pid=fork();
if (pid==0) return make_proc(counter, x);
wait(NULL);
}
}
--------------------
int main(int argc, char **argv)
{
int x=getpid();
make_proc(10, x);
return 0;
}
I want to fork three child process in one parent.
And the following is my C++ code:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
using namespace std;
int main()
{
pid_t pid;
for (int i = 0; i < 3; i++)
{
pid = fork();
if (pid < 0)
{
cout << "Fork Error";
return -1;
}
else if (pid == 0)
cout << "Child " << getpid() << endl;
else
{
wait(NULL);
cout << "Parent " << getpid() << endl;
return 0;
}
}
}
Now my output is :
Child 27463
Child 27464
Child 27465
Parent 27464
Parent 27463
Parent 27462
How should I modify my program to get the output like the following?
Child 27463
Child 27464
Child 27465
Parent 27462
What I mean is that these THREE children need to belong to the same ONE parent, can anybody give me some suggestion ?
Thank you all. :)
You should exit the execution of the child processes. Otherwise, they continue forking also
pid_t pid;
for(i = 0; i < 3; i++) {
pid = fork();
if(pid < 0) {
printf("Error");
exit(1);
} else if (pid == 0) {
cout << "Child " << getpid() << endl;
exit(0);
} else {
wait(NULL);
cout << "Parent " << getpid() << endl;
}
}
There are two issues:
children zero and one continue with the for loop, spawning further processes;
the "parent" branch terminates instead of continuing with the loop.
The following will produce the output you want:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
using namespace std;
int main()
{
pid_t pid;
for (int i = 0; i < 3; i++)
{
pid = fork();
if (pid < 0)
{
cout << "Fork Error";
return -1;
}
else if (pid == 0) {
cout << "Child " << getpid() << endl;
return 0;
} else {
wait(NULL);
if (i == 2) {
cout << "Parent " << getpid() << endl;
}
}
}
}
When I run it, I get
Child 4490
Child 4491
Child 4492
Parent 4489
Move your return 0 from the last condition to the middle one:
if (pid < 0)
{
cout << "Fork Error";
return -1;
}
else if (pid == 0) {
cout << "Child " << getpid() << endl;
return 0;
}
else
{
wait(NULL);
cout << "Parent " << getpid() << endl;
}
This way the parent will continue to loop, and the children will terminate instead of looping.