Running 3 child processes - c++

I have three child process and one parent.
I want the program runs in that order [ Child1 then child2 then child3 then parent ].
I have been trying to do with the follwing code but it dose not give me right sequence!
Code:
#include<iostream>
#include<string.h>
#include<fstream>
#include<cstdlib>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main()
{
pid_t ch11;
pid_t ch22;
pid_t ch33;
int ch1 = fork();
int ch2 = fork();
int ch3 = fork();
if (ch1==0) //child1
{ cout<<"this is child 1\nGoing from 1 to child 2 ...\n\n";
exit(0);
}
else if ( ch2==0)
{ waitpid(ch11,0,0);
cout<<"This is child 2\nGoing from 2 To Child 3 ...\n\n";
exit(0);
}
else if (ch3==0)
{ waitpid(ch22,0,0);
cout<<"This is child 3\nFineshed !! going from 3 to parent\n\n";
exit(0);
}
else
{ waitpid(ch33,0,0);
cout<<"This is parent , waited the whole childes to finish !!\n\n";
exit(0);
}
return 0 ;
}
Output:
ubuntu#ubuntu-desktop:~$ c++ a.cpp -o p1
ubuntu#ubuntu-desktop:~$ ./p1
This is child 2
Going from 2 To Child 3 ...
this is child 1
Going from 1 to child 2 ...
this is child 1
Going from 1 to child 2 ...
this is child 1
Going from 1 to child 2 ...
This is child 2
Going from 2 To Child 3 ...
This is child 3
Fineshed !! going from 3 to parent
this is child 1
Going from 1 to child 2 ...
This is parent , waited the whole childs to finish.
I know that it will be solved by using waitpid() function , I think im using the waitpid() wrong.

Here's a better instrumented version of your code; it includes the PID in the output, and the outputs are one line each.
#include <iostream>
#include <cstdlib>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
int main()
{
int ch1 = fork();
int ch2 = fork();
int ch3 = fork();
if (ch1 == 0) // child1
{
cout << (int)getpid() << ": This is child 1 - Finished\n";
exit(0);
}
else if (ch2 == 0)
{
waitpid(ch1, 0, 0);
cout << (int)getpid() << ": This is child 2 - Finished\n";
exit(0);
}
else if (ch3 == 0)
{
waitpid(ch2, 0, 0);
cout << (int)getpid() << ": This is child 3 - Finished!\n";
exit(0);
}
else
{
waitpid(ch3, 0, 0);
cout << (int)getpid() << ": This is parent - waited for all children to finish!\n";
exit(0);
}
return 0;
}
Sample output:
$ ./3kids
40287: This is child 3 - Finished!
40285: This is child 1 - Finished
40286: This is child 2 - Finished
40290: This is child 1 - Finished
40289: This is child 2 - Finished
40288: This is child 1 - Finished
40284: This is parent - waited for all children to finish!
40291: This is child 1 - Finished
$
As you can see, there is one process that considers itself to be child 3, two processes that consider themselves to be child 2, and four processes that consider themselves to be child 1 and one that considers itself to be the parent. This is consistent with the unconstrained forking which creates 8 processes.
To have 3 children only, and to wait for each in turn, you need code more like:
#include <iostream>
#include <cstdlib>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
void child(int n)
{
flush(cout); // No pending output
int pid = fork();
if (pid < 0)
cerr << (int)getpid() << ": failed to fork\n";
else if (pid == 0)
{
cout << (int)getpid() << ": This is child " << n << " - Finished\n";
exit(0);
}
else
{
int corpse;
int status;
while ((corpse = wait(&status)) != -1)
cout << (int)getpid() << ": PID " << corpse << " exited with status "
<< status << "\n";
}
}
int main()
{
child(1);
child(2);
child(3);
cout << (int)getpid() << ": This is parent - waited for all children to finish!\n";
return 0;
}
Sample output:
$ ./3kids
40336: This is child 1 - Finished
40335: PID 40336 exited with status 0
40337: This is child 2 - Finished
40335: PID 40337 exited with status 0
40338: This is child 3 - Finished
40335: PID 40338 exited with status 0
40335: This is parent - waited for all children to finish!
$

Despite your comment "the code is working but it gives me the wrong sequence of executing" the whole thing is still completely incorrect and it is obvious you did not understand what other people tried to say, hence I'll make an attempt here.
int main()
{
pid_t ch11;
pid_t ch22;
pid_t ch33;
What is the purpose of these variables?
int ch1 = fork();
Have you read fork manpage? It clearly states when a child process is created it returns 0 in the child and pid in the parent. It can also fail, so you should have checked for that.
With this in mind....
int ch2 = fork();
Both the child and the parent reach this line. Hence previously created child forks as well.
int ch3 = fork();
Guess what.
if (ch1==0) //child1
{ cout<<"this is child 1\nGoing from 1 to child 2 ...\n\n";
Except you are not (see below).
exit(0);
Should be _Exit.
}
else if ( ch2==0)
{ waitpid(ch11,0,0);
What? ch11 is not even initialized, so what was this supposed to accomplish?
Do you compile your code with warnings enabled?
In general I don't know if you were trying to make the children fork and thus create a chain of for processes with parent<->child relationship or you wanted 3 children of the same parent process. If the latter this is just bad, if the former this is even more wrong since you would not be able to just wait for such a process.
[snip the rest]
Finally, let's address
the wrong sequence of executing
What?
There are no guarantees whatsoever as to the order of execution of your processes. In fact any number of them can execute for any amount of time and be scheduled out multiple times before any other number of them even gets a chance to run.
Given what was shown up to this point I'm inclined to guess you either misunderstood your homework assignment or are approaching it quite "unconventionally". Either way, I strongly recommend you state the actual problem which was supposed to be addressed with your code.

Related

How can I resume a stopped process?

Following this documentation, I am testing how to stop and resume a process. I have basic code to test as follows:
#include <iostream>
#include <csignal>
#include <unistd.h>
int main() {
std::cout << "Hello" << std::endl;
int pid = getpid();
kill(pid, SIGSTOP);
kill(pid, SIGCONT);
std::cout << "Bye" << std::endl;
return 0;
}
The output is:
Hello
It stops the process, but it never resumes it. How should I fix it?
A solution, if a bit complicated, is to create a child process to start and stop the parent. Here is a small code example, that might help:
#include <iostream>
#include <csignal>
#include <unistd.h>
int pid; //Include declaration outside so it transfers to the child process
int main() {
std::cout << "Hello" << std::endl;
pid = getpid();
int returned_pid = fork(); //Duplicate process into 2 identical processes
if(returned_pid) {
// If it is the parent process, then fork returns the child process pid
// This is executed by the parent process
usleep(1000); // Sleep a millisecond to allow for the stop command to run
} else {
// If fork returns 0, then it is the child process
// The else is executed by the child process
kill(pid, SIGSTOP); // Stop parent process
usleep(3000000); // Delay 3 seconds
kill(pid, SIGCONT); // Resume parent process
}
if(returned_pid) { // Only print if parent process
std::cout << "Bye" << std::endl;
}
return 0;
}
Clarification: The fork command returns 2 different values in the 2 processes: 0 in the child, and the pid of the child process in the parent.
Other note: When running this in a terminal, it will look weird, as the terminal may note that the process was stopped and give a new command line, but then the process resumes, so prints Bye over it. Just a note.

Child process becomes Defunct after fork and exec

I am learning fork and exec and creating multiple child processes using fork and execlp and all I do in the child process is let it sleep. Basically I just want all my child to be alive. But as soon as i start my monitor.cpp which creates processes all of the child exit immediately and they do defunct!
Monitor which forks multiple children
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
for(size_t i=0; i<std::stoi(argv[1]) ; ++i)
{
int pid = fork();
if(pid == 0)
{
execlp("child", "child", std::string(std::to_string(i)).c_str(), (char *)0);
std::cout << "child exiting " << std::endl;
exit(1);
}
else if(pid > 0)
{
std::cout <<"child started with " << pid << std::endl;
}
else
{
std::cout << "fork failed" << std::endl;
}
}
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(100000));
}
return 0;
}
Child Code
#include <iostream>
#include <thread>
#include <chrono>
int main(int argc, char* argv[])
{
std::cout << " child started with id " << argv[1] << std::endl;
std::cout <<"child sleeping " << argv[1] << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1000));
std::cout << "child exiting " << argv[1] << std::endl;
return 0;
}
Output:
child started with 1834
child started with 1835
child exiting
child started with 1836
child exiting
child started with 1837
child started with 1838
child started with 1839
child exiting
child started with 1840
child started with 1841
child exiting
child started with 1842
child started with 1843
child exiting
child exiting
child exiting
child exiting
child exiting
child exiting
ps -ef shows all of my child processes as Defunct even though my parent is still alive.
Can you please explain what am I missing?
From the 'execlp' man page:
The exec() functions only return if an error has occurred. The return value is -1, and errno is set to indicate the error.
Since "child exiting" is being printed in two places, it's not obvious if it's exiting. You need to check it's return value and errno.
You need to reap the child-process as they exit. This is done using wait or waitpid calls.
Until the parent has done this, they will be visible as defunc / zombie processes. (init, process 1, is responsible for reaping all process that do not have a parent after they exit)

Why does the child of this class does not print?

I have made a class that is supposed to handle a subprocess but when I put a test print inside nothing happens, can someone tell me why ?
I have tried different types of print and combinations of fflush but it didn't solve the problem.
Here are my files:
Kitchen.cpp
Kitchen::Kitchen()
{
int wstatus;
this->_pid = fork();
if (this->_pid == 0) {
std::cout << "child: " << this->_pid << std::endl;
} else if (this->_pid == -1) {
throw("No child");
} else {
std::cout << "parent: " << this->_pid << std::endl;
waitpid(this->_pid, &wstatus, 1);
}
}
Kitchen::~Kitchen()
{
if (this->_pid > 0)
kill(this->_pid, SIGKILL);
}
Kitchen.hpp
#pragma once
#include <signal.h>
#include <unistd.h>
class Kitchen {
public:
Kitchen();
~Kitchen();
private:
pid_t _pid;
};
Reception.cpp
int Reception::run_shell(void)
{
this->_kitchens.push_back(Kitchen());
return (0);
}
Reception.hpp
#pragma once
#include <iostream>
#include <sstream>
#include "Kitchen.hpp"
class Reception
{
public:
Reception();
~Reception();
void repart(std::vector<Package> packed_order);
bool is_order(std::string input);
std::vector<Package> pack(std::string input);
int run_shell(void);
private:
std::vector<Kitchen> _kitchens;
};
main.cpp
int main(void)
{
Reception reception;
return (reception.run_shell());
}
Right now only the parent prints where as I would like both process to print.
Note that this code works outside of the class.
is it better now ?
Yes, better.
I copied your code to my Lubuntu 18.04, and using g++ 7.3.0-27, got the thing to compile.
The copied code on my system reproduced your error.
Hmmm.
So, I went looking for, and quickly found, my most recent experiment with fork. I do not understand why it works, and yours does not, they look similar enough to me.
I use a switch instead of your nested if-then-else's ... perhaps there exists a glitch in the nested if-then-else's? a faulty char transfer? But I doubt it.
So ... for pragmatic reasons, I (minimally?) changed your code to match my example.
Perhaps you can ask a better question as to why this seems to work, and in your version does not.
Hope this helps:
#include "../../bag/src/dtb_chrono.hh"
using namespace std::chrono_literals; // support suffixes like 100ms, 2s, 30us
#include <iostream>
using std::cout, std::cerr, std::flush, std::endl;
#include <string>
using std::string;
#include <thread>
using std::this_thread::sleep_for;
#include <vector>
using std::vector;
#include <cstring>
using std::strerror;
#include <unistd.h> // fork
#include <sys/wait.h> // waitpid
#include <cassert>
class Kitchen
{
pid_t child_pid;
time_t pt0; // child start time 0
time_t ct0; // parent start time 0
public:
Kitchen()
{
pt0 = time(0) + 2;
ct0 = time(0) + 1;
// On success, the PID of the child process is returned in the
// parent, and 0 is returned in the child.
//
// On failure, -1 is returned in the parent, no child process is
// created, and errno is set appropriately.
child_pid = fork();
switch (child_pid)
{
case -1: { errnoExit (errno, "\n fork fail: ", -12); } break;
case 0: // child
{
std::cout << "\n i am child: " << child_pid << endl;
ChildProcess();
}
break;
default: // parent
{
std::cout << "\n i am parent, child_pid: " << child_pid << flush;
ParentProcess();
}
} // switch(child_pid)
} // Kitchen
~Kitchen()
{
if (child_pid > 0)
{ }; // { kill(child_pid, SIGKILL)};
}
void ChildProcess(void)
{
int i = 0;
do {
i += 1;
cout << "\n child " << i;
std::this_thread::sleep_for(100ms);
if (time(0) > ct0) break;
}while (true);
cout << "\n*** Child complete ***" << '\n';
}
void ParentProcess(void)
{
int i = 0;
do {
i += 1;
cout << "\n parent " << i ;
std::this_thread::sleep_for(100ms);
if (time(0) > pt0) break;
}while (true);
int wstatus;
waitpid(child_pid, &wstatus, 1); // see output -
// waitpid not effective because parent runs longer than child
// but causes no harm ...
//
// TBD - when parent run is shorter than child?
// appears that parent end halts child?
cout << "\n*** Parent complete ***" << '\n';
}
private:
void errnoExit(int err_no, const string message, int id) {
assert(0 != err_no); cerr << message << strerror(err_no);
assert(id < 0); exit(id); }
}; // class Kitchen
class Reception
{
public:
Reception() = default;
~Reception() = default;
int operator()(int argc, char* argv[]) { return run_shell(argc, argv); }
//void repart(std::vector<Package> packed_order);
//bool is_order(std::string input);
//std::vector<Package> pack(std::string input);
int run_shell(int /*argc*/, char** /*argv[]*/)
{
_kitchens.push_back(Kitchen());
return (0);
}
private:
vector<Kitchen> _kitchens;
}; // class Reception
int main(int argc, char* argv[]) { return Reception()(argc, argv); }
Typical Output:
i am parent, child_pid: 6727
i am child: 0
parent 1
child 1
parent 2
child 2
parent 3
child 3
parent 4
child 4
parent 5
child 5
parent 6
child 6
parent 7
child 7
parent 8
child 8
parent 9
child 9
parent 10
child 10
parent 11
child 11
parent 12
child 12
parent 13
child 13
parent 14
child 14
parent 15
child 15
parent 16
child 16
parent 17
child 17
parent 18
child 18
*** Child complete ***
parent 19
parent 20
parent 21
parent 22
parent 23
parent 24
parent 25
parent 26
parent 27
parent 28
*** Parent complete ***
The last else lacks curly braces, waitpid(this->_pid, wstatus, 1); is executed by both child and parent...
The parent process needs to be told to wait for any child processes to complete. I noticed your final else condition is missing the parentheses so only the one line after the else will be executed.
The other issue is the pointer wstatus. Because it's a pointer that isn't initialized, I'm not sure which behavior will be expressed. Change it to an int and in the waitpid call, use &wstatus.

Child Process runs even after parent process has exited?

I was writing a code for a research program. I have following requirement:
1. Main binary execution begins at main()
2. main() fork()
3. child process runs a linpack benchmark binary using execvp()
4. parent process runs some monitoring process and wait for child to exit.
The code is below:
main.cpp
extern ServerUncorePowerState * BeforeStates ;
extern ServerUncorePowerState * AfterStates;
int main(int argc, char *argv[]) {
power pwr;;
procstat st;
membandwidth_t data;
int sec_pause = 1; // sample every 1 second
pid_t child_pid = fork();
if (child_pid >= 0) { //fork successful
if (child_pid == 0) { // child process
int exec_status = execvp(argv[1], argv+1);
if (exec_status) {
std::cerr << "execv failed with error "
<< errno << " "
<< strerror(errno) << std::endl;
}
} else { // parent process
int status = 1;
waitpid(child_pid, &status, WNOHANG);
write_headers();
pwr.init();
st.init();
init_bandwidth();
while (status) {
cout << " Printing status Value: " << status << endl;
sleep (sec_pause);
time_t now;
time(&now);
struct tm *tinfo;
tinfo = localtime(&now);
pwr.loop();
st.loop();
data = getbandwidth();
write_samples(tinfo, pwr, st, data.read_bandwidth + data.write_bandwidth);
waitpid(child_pid, &status, WNOHANG);
}
wait(&status); // wait for child to exit, and store its status
//--------------------This code is not executed------------------------
std::cout << "PARENT: Child's exit code is: "
<< WEXITSTATUS(status)
<< std::endl;
delete[] BeforeStates;
delete[] AfterStates;
}
} else {
std::cerr << "fork failed" << std::endl;
return 1;
}
return 0;
}
What is expected that the child will exit and then parent exits but due to some unknown reason after 16 mins parent exits but child is still running.
Normally It is said that when parent exits the child dies automatically.
What could be the reason for this strange behavior???
Normally It is said that when parent exits the child dies automatically.
Well this is not always true, it depends on the system. When a parent process terminates, the child process is called an orphan process. In a Unix-like OS this is managed by relating the parent process of the orphan process to the init process, this is called re-parenting and it's automatically managed by the OS. In other types of OS, orphan processes are automatically killed by the system. You can find more details here.
From the code snippet I would think that maybe the issue is in the wait(&status) statement. The previous loop would end (or not be executed) when the return status is 0, which is the default return value from your final return 0 at the end, that could be yielded by the previous waitpid(child_pid, &status, WNOHANG) statements. This means that the wait(&status) statement would wait on a already terminated process, this may cause some issues.

Why am I having to terminate my program manually?

I have a program that should launch another process and work simultaneously with it. I am using fork() and system() to accomplish this. I have code verifying that that my system() call returns, but every time I execute I have to manually end the execution by typing ctrl c. I can tell that one of my processes terminates, but I am not quite sure which one. I believe it is the parent. Both should be caught by return statements though.
Here is the parent process code (forkWaitTest):
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int main(void)
{
pid_t childPID;
int status;
childPID = fork();
if(childPID >=0)
{
if(childPID == 0)
{
cout <<"I'm the fork child";
cout.flush();
status=system("child");
cout << "status = " << status;
//exit(0);
//cout << "Am I getting here?";
}
else{
cout << "I am the parent and can keep doing things ";
int y=1;
int x=7;
cout<< y+x << " ";
}
}
return 0;
}
This is the child process that is called
#include <stdio.h>
int main(int argc, char *argv[] )
{
printf("I am the child\n");
return 0;
}
Here is my output:
-bash-4.2$ forkWaitTest
I am the parent and can keep doing things 8 I'm the fork child-bash-4.2$ I am the child
status = 0
Your parent DID terminate. Let's look at your output:
-bash-4.2$ forkWaitTest
I am the parent and can keep doing things 8 I'm the fork child-bash-4.2$ I am the child
status = 0
Now let's look at that more closely, particularly this bit:
I'm the fork child-bash-4.2$
See, right in the middle, it says bash-4.2$. That's the command prompt after the parent terminates. Then the child runs and also exits, but you are confused as it prints after the bash prompt. Your ^C merely prints the next line.
To verify, press return a few times rather than ^C.
Make sure your messages end with newlines (add << endl to the outputs, for example).
I see your bash prompt (the -bash-4.2$) mixed up with the other outputs, partly because you don't have newlines in the outputs, and partly because your code doesn't show any attempt to wait for children to die. This means that your process did die.
You could type: ls -l and the shell would execute that command because it is waiting for you to type something. When you interrupt it (the shell), it prompts again, but it would have taken your input even without the interrupt.
With a slightly modified version of the child:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("I am the walrus (%d)\n", (int)getpid());
return 0;
}
and a slightly modified version of the parent:
#include <cstdlib>
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
int main(void)
{
pid_t childPID;
int status;
childPID = fork();
if (childPID >= 0)
{
if (childPID == 0)
{
cout << "I'm the forked child (" << getpid() << ")\n";
cout.flush();
status = system("child");
cout << "status = " << status << endl;
cout << "Am I getting here?\n";
return 0;
}
else
{
cout << "I am the parent and can keep doing things ";
int y = 1;
int x = 7;
cout << y + x << endl;
}
}
int corpse;
while ((corpse = wait(&status)) != -1)
cout << "PID " << corpse << " exited with status " << status << endl;
return 0;
}
and with a prompt Osiris JL:, an example of the output I get is:
Osiris JL: ./parent
I am the parent and can keep doing things 8
I'm the forked child (3192)
I am the walrus (3193)
status = 0
Am I getting here?
PID 3192 exited with status 0
Osiris JL:
Note that the 'child' program is run by a child of the parent process's own child (that's why the getpid() values are printed). And the wait() in a loop in the parent process ensures that the child has died before the parent dies. Given the structure of the child process, which uses the system() function, the grandchild process (running the partly misnamed child process) has exited before the child exits before the parent exits. Omit the wait() loop and the parent can easily exit before the child and grandchild do:
Osiris JL: ./parent
I am the parent and can keep doing things 8
I'm the forked child (3207)
Osiris JL: I am the walrus (3208)
status = 0
Am I getting here?
ls -ld parent* child*
-rwxr-xr-x 1 jleffler staff 8784 Sep 20 15:57 child
-rw-r--r-- 1 jleffler staff 122 Sep 20 15:57 child.cpp
drwxr-xr-x 3 jleffler staff 102 Sep 20 15:57 child.dSYM
-rwxr-xr-x 1 jleffler staff 9808 Sep 20 16:02 parent
-rw-r--r-- 1 jleffler staff 858 Sep 20 16:02 parent.cpp
drwxr-xr-x 3 jleffler staff 102 Sep 20 16:02 parent.dSYM
Osiris JL: