Need help in implementing conditional outputs using the fork() function - c++

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";
}

Related

Using execvp with parameters

I want to know how can I run a program with parameters using fork() and execvp().
I want to run the program test and passed the parameter flag.
I am using the variable args to capture the string start /test flag. This code snippet below is contained inside a conditional statement that checks for the parsed string start /test -flag.
arguments[0] = "/test"
arguments[1] = "-flag"
char * arguments[3];
arguments[0] = (char*)args[1].c_str();
arguments[1] = (char*)args[2].c_str();
arguments[2] = NULL;
cout << "Arguments[1] = " << arguments[1] << endl;
pid_t pid = fork();
// ERROR
if (pid == -1)
perror("ERROR: Failed to fork");
// Child
if (pid == 0)
{
cout << "child: " << pid << endl;
if (execvp (arguments[0], arguments) == -1)
{
perror("exec");
}
}
// Parent
if (pid > 0)
{
wait(0);
cout << "parent: " << pid << endl;
}
Does this mean that my program test is getting passed the parameter flag as an argument? In other words, ARGV[0]: flag?
int main (int argc, char **argv)
{
cout << "YOU ENTERED: " << argc << "ARGUMENTS" << endl;
cout << "ARGV[0]: " << argv[0] << endl;
return 0;
}

Using SIGINT and SIGTSTP to handle foreground processes a unix shell

I have some questions regarding the use of SIGINT and SIGTSTP in relation to managing processes in my own unix shell. But first of the code here:
void execute(vector<char *> argvv, bool x){
pid_t pid;
int status;
int error;
pid = fork();
a = pid;
argvv.push_back(NULL);
if(pid == -1){
cout << "error" << endl;
}else if(pid == 0){
error = execvp(argvv[0],argvv.data());
if(error == -1){
exit(-1);
}
// In Child Process
}else{
// If no "&", then wait for process
if(x == false){
if(wait(&status) != pid){
perror("wait()");
}
}else{
cout << "Pid des Hintergrundprozesses: " << pid << endl;
}
// in parent process
}
}
This function just receives the entered operation and parameters, forks a new process and executes it.
Now my signalhandler functions:
void signalHandlerSigInt(int signum){
cout << "Interrupt Signal (" << signum <<") received." << endl;
kill(a,SIGINT);
cout << "Killed Process: " << a << endl;
}
void signalHandlerSigTStp(int signum){
cout << "Interrupt Signal (" << signum <<") received." << endl;
kill(a,SIGTSTP);
cout << "Stop process..: " << a << endl;
}
and my main.cpp:
int main(int agc, char** argv) {
bool opBackground;
string operation;
vector<string> arguments;
vector<char *> argvv(arguments.size() + 1);
signal(SIGINT, signalHandlerSigInt);
signal(SIGTSTP, signalHandlerSigTStp);
while(true){
cout << "myshell>";
getline(cin,operation);
if(operation == "logout"){
logout();
}else{
opBackground = befehlUebersetzen(operation, &arguments);
vector<char *> argvv(arguments.size() + 1);
for(size_t i = 0; i != arguments.size(); ++i){
argvv[i] = &arguments[i][0];
}
execute(argvv, opBackground);
arguments.clear();
}
}
return 0;
}
The shell itself works fine, I now need to extend it to be able to kill the foreground process by pressing CTRL+C or stop the process with CTRL+Z.
I think I understood what a Signalhandler does, but is kill(a,SIGINT) the right way to transmit the signal SIGINT to my process? ("a" is a global variable for my forked pid, that means the last process I forked).
My problem is, when starting a process in the background and then start another process in the foreground it kills both processes when pressing CTRL+C.
Also the SIGTSTP signalhandler doesnt seem to work at all (does nothing - process just keeps running in the foreground).
Am I completely wrong with what im doing?

How to track termination/running of child process that is not being "waited" for?

I have an assignment where I have to write a subshell in C++. Essentially, I am forking (if the input is not jobs or exit) and in the child process, I am calling exec to run the command. It needs to run alongside the parent process, so for example if I call sleep 100, the program should immediately be ready to run the next command since the parent is not "waiting" for it since I am using WNOHANG. However, my issue is when I need to track the actual state- if sleep is still running, I want to be able to get that the command is still running, but I am unable to do so. It always shows up as exited, when I use the various macros. I have no idea how to approach this differently and would appreciate some guidance.
(i didn't include the declarations of the variables since the editor on this website was messing it up for some reason)
do{
cout << "# ";
getline(cin, input);
if (input == "jobs")
{
cout << "Process ID | State | Command " << endl;
cout << "-----------+--------------+-----------------------------------------------" << endl;
//jobs stuff goes here, need to print pids, states, and commands
if(counter == 0)
{
cout << " [NO PROCESSES] " << endl;
}
else
{
for(i = 0; i < counter; i++)
{
cout << pidArray[i] << " ";
cout << statusArray[i] << " ";
cout << cmdArray[i] << endl;
}
}
}
else
{
cmdArray[i] = input;
i++;
counter++;
pid = fork();
if( pid == 0)
{
execl("/bin/sh", "sh", "-c", input.c_str(), (char *)0);
//break;
}
else if (pid == -1)
{
break;
}
else
{
pidArray[i-1] = pid;
//int rc = waitid(P_PID, pid, NULL, WNOHANG);
// int rc =waitpid(pid, &status, WNOHANG | WNOWAIT );
//exitChecker = waitpid(pid, &status, WNOHANG);
usleep(100000);
if (WIFEXITED(status))
{
cout << "terminated" << endl;
}
else
{
cout << "running" << endl;
}
}
}
}while(input != "exit");
return 0;
}
Thanks in advance.

Trace parent process with PID and display it's child and grandchild PID

I managed to output the correct order of process id's for each individual process but my issue is that I can't display the child's PID.
My program is able to print parent's PID, and grandchild's PID. I do see the child's PID but it displays as parent's PID.
How can I compute child's PID and add it to my code? I would like my output to display parent's PID, child's PID, and grandchild's PID.
#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
const char *message;
int n;
int exit_code;
cout << "\nfork program starting\n";
pid = fork();
switch ( pid ) {
case -1:
cout << "Fork failure!\n";
return 1;
case 0:
pid = fork();
cout << "Parent PID = " << getppid() << endl;
switch ( pid ) {
case -1:
cout << "Fork Failure!\n";
return 1;
case 0:
cout << "Grandchild finished: PID = " << getpid() << endl;
message = "This is the child\n";
n = 5;
exit_code = 9;
break;
}
}
//waiting for child to finish
if ( pid != 0 ) { //parent
int stat_val;
pid_t child_pid;
child_pid = wait( &stat_val ); //wait for child
if (WIFEXITED (stat_val))
cout << "child exited with code " << WEXITSTATUS (stat_val) << endl;
else
cout << "child terminated abnormally!" << endl;
}
exit ( exit_code );
}
it does not seem you are prining the child PID before the 2nd fork()
change:
case 0:
pid = fork();
cout << "Parent PID = " << getppid() << endl;
switch ( pid ) {
case -1:
cout << "Fork Failure!\n";
return 1;
[...]
}
to:
case 0:
cout << "Child PID = " << getpid() << endl;
pid = fork();
cout << "Parent PID = " << getppid() << endl;
switch ( pid ) {
case -1:
cout << "Fork Failure!\n";
return 1;
[...]
}
here, just after the first line, print getpid(), instead of printing it later. Then use pid2 or different identifier, instead of using same pid. That will solve all your problems.
case 0:
pid = fork();
cout << "Parent PID = " << getppid() << endl;
switch ( pid ) {
case -1:
cout << "Fork Failure!\n";
return 1;
case 0:
cout << "Grandchild finished: PID = " << getpid() << endl;//
Why the problem happened? Because only after 'second case 0', that is child of the child your are printing getpid(), which apparently prints grand child's PID. Instead you should try 'default:' which will work for first level child & second level parent (that is not grand child since not pid!=0). Notably you did not allow case for parent. you gave one case for failure (-1) and another for child(0) and none for parent.

fork mulitple child in one parent

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.