This question already has answers here:
Why do processes I fork get systemd as their parent?
(3 answers)
Closed 6 years ago.
I have been trying to learn about fork and processes. I just encountered a small problem with this piece of code and was trying to understand why?.
I was trying to duplicate a process by a system call Fork and with the value of pid being positive, it hit the parent and its getpid() was returned. And simultaneously it hit the child and its getpid() was returned. But the problem was, when I called up the getppid() here, it was expected to show its parent's process identifier, which happened to be 3370.
But upon compilation and execution of this file, it showed the value of getppid() as 1517 (not parent's id).
I am using ubuntu 14.04 LTS on Oracle VM VirtualBox (32-bit O.S.). The code of this forking.cpp file is as follows:
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <cstdlib>
using namespace std;
int main()
{
pid_t pid1;
pid1 = fork();
if(pid1 == -1)
{
cout << "No child process formed: " << getpid() <<endl;
}
else if(pid1 == 0)
{
cout << "Child has been formed: " << getpid()<< " and its parent's id: " << getppid() << endl;
}
else if(pid1 > 0)
{
cout << "Parent process has been called: " << getpid() << endl;
}
cout << "END of Stuffs" << endl;
return 0;
exit(0);
}
For compilation, I was using the command g++ forking.cpp on terminal and for executing, ./a.out.
Then it showed this:
Parent process has been called: 3370
END of Stuffs
Child has been formed: 3371 and its parent's id: 1517
END of Stuffs
shashish-vm#shashishvm-VirtualBox:~/Desktop$
I know that trivially, if a parent dies before its child, the child is automatically adopted by the original "init" process, with PID 1. But here it is definitely not this case.
This situation occurs when the parent process terminates before the execution of getppid(). Use wait(NULL) at the end the parent to solve the problem.
Related
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)
I have the following two simple programs:
bye.cc
#include <iostream>
int main()
{ std::cout << "Bye bye bye world" << std::endl; }
hello.cc
#include <cstdlib>
#include <unistd.h>
#include <sys/wait.h>
#include <iostream>
using namespace std;
int main()
{
int status;
cout << "Hello world" << endl;
int pid = fork();
if (pid != 0) {
cout << "I am parent - " << pid << endl;
// wait for child to finish up......
cout << "Waiting for child to finish" << endl;
wait(&status);
cout << "Child finished, status " << status << endl;
} else {
cout << "--- I am child - " << pid << endl; // **Note**
execl("bye", "");
cout << "--- I am sleeping" << endl;
sleep(3);
exit(11);
}
}
In hello.cc, if the line marked "Note" is enabled (not commented), I get the expected behavior, sleep(3) is not executed, and "bye" is executed, expected msg printed to console.
$ ./hello
Hello world
I am parent - 27318
Waiting for child to finish
--- I am child - 0
Bye bye bye world
Child finished, status 0
However, when the line marked "Note" is commented, "bye" is NOT executed, and sleep(3) is performed.
$ ./hello
Hello world
I am parent - 27350
Waiting for child to finish
--- I am sleeping
Child finished, status 2816
Can someone please help me understand what might be going on. What I found very odd, if I replace the "cout" with a printf(), then the sleep performed.
Thank you,
Ahmed.
According to the spec, the argument list to execl must be terminated by a NULL pointer (i.e. (char *)0, not "").
Changing the nearby code is just changing what happens to be on the stack when you invoke execl. As written, the program's behavior is undefined.
P.S. Always check the return value of library routines for errors.
the exec family of functions, when successful, do not return.
That is why you do not see the sleep comment when the execl() is executed.
As I have just started with these concepts I might be missing out a few elementary things. I was trying to link the parent and the child processes (created by fork() function) using pipe. In the parent process, I wanted to write in the pipe descriptor (af[1]) and after closing up the write end, I wanted to read from the read end of the pipe with descriptor (af[0]) in the child process.
Here is my code:
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <cstdlib>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
using namespace std;
int main()
{
pid_t pid1;
pid1 = fork();
int af[2],nbytes,wbytes;
pipe(af);
char inside[20];
if(pid1 == -1)
{
cout << "No child process formed: " << getpid() <<endl;
exit(1);
}
else if(pid1 == 0)
{ cout<< "inchild" <<endl;
close(af[1]);
nbytes = read(af[0],inside,strlen(inside));
cout << "read bytes: "<< nbytes << endl;
cout << "child(read) inside descriptor: " << inside << endl;
close(af[0]);
cout << "in child's end" << endl;
exit(0);
}
else
{ cout<< "inparent" << endl;
close(af[0]);
wbytes = write(af[1],"Hello World",12);
cout<< "wrote bytes: " << wbytes<<endl;
cout << "Parent(write) inside string: " << af[1] << endl;
close(af[1]);
cout << "in parent's end" << endl;
exit(0);
}
return 0;
}
Then I was expecting this to run as follows:
Goes into the parent -> write string,
Close write end,
Goes into the child -> read string into inside,
Show result of string (Hello World),
Close read end.
But what I was getting here is this result:
inparent
shashish-vm#shashishvm-VirtualBox:~/Desktop$ inchild
read bytes: 0
child(read) inside descriptor:
A��M�N��sf�
in child's end
And it was still not terminating.
I was using Ubuntu 14.04 LTS on Oracle VM VirtualBox (32-bit O.S.). And I have no idea why it was doing like this. I knew it is the job of the scheduler to switch the processes but still pipe functionality of IPC was not working there. The write process occurred even if I removed close(af[0]) statement but still the reading was not happening properly.
You problem is that you open the pipe after calling fork. This means the parent and child have different pipes. You can fix it by moving the call to pipe before the fork to create a single linked pipe.
The goal of this program is to fork and have the child sleep while parent loops infinitely waiting for an interrupt. When I hit ^C, it calls the void parent function. This part works however, the message from the kill ( pid, SIGALRM ) is not working. I checked and pid is the correct process ID for the child.
I've searched for awhile, but I haven't found what I'm doing wrong. I used the kill ( pid, SIGALRM ) before from the child process to the parent but I can't figure out why this isn't working..
#include <signal.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int pid;
void parent ( int sig )
{
kill ( pid, SIGALRM );
cout << "I'm a parent " << getpid() << " My child is " << pid << endl;
}
void child ( int sig )
{
cout << "I am " << getpid() << "my parent is " << getppid()<< endl;
cout << "Use ctrl+backslash to actually end the program" << endl;
}
int main()
{
pid = fork();
if(pid == 0)
{ //Child process
cout << "Child pid = " << getpid() << " Waiting for interrupt." << endl;
(void) signal ( SIGALRM, child );
pause();
}
else if(pid > 0)
{ //Parent
sleep(2);
cout << "child pid = " << pid << endl;
struct sigaction act;
act.sa_handler = parent;
sigemptyset ( &act.sa_mask);
sigaction (SIGINT, &act, 0);
while(1)
{
sleep ( 1 );
}
}
return 0;
}
Ok, so I figured out the problem.
When I was pressing ^C, it would catch the interrupt in the main process, but kill the child process. When I ran a system("ps") from inside the program, it showed the child a.out process to be defunct.
To fix this I added the following to the child's process:
struct sigaction act;
act.sa_handler = CHILD_PRESERVER;
sigemptyset ( &act.sa_mask);
sigaction (SIGINT, &act, 0);
Where CHILD PRESERVER was a dummy function that did nothing except keep it alive.
It doesn't see that this solution is very elegant, so if anyone has a more correct way of doing this please post it.
You can do the same thing as your sigaction solution by just using signal(SIGINT, SIG_IGN);
The thing that tripped you up initially (and often trips up new programmers dealing with ctrl-C and signals) is that ctrl-C sends a signal to AN ENTIRE PROCESS GROUP, rather than to a single process -- every process in the group will get the signal. The process group the signal is sent to is the foreground process group of the terminal.
So this gives you lots of ways of dealing with/controlling ctrl-C interrupts. You can have each process install its own SIGINT handler (as you have done). Or you can carefully manage your process groups, putting children into their own process group (which will generally not be the foreground process group), so they won't get the signal in the first place.
You manage process groups with the setpgrp(2)/setpgid(2) system call.
This is my code... I don't know why I'm get an error segment... could somebody explain the reason to me?
#include <iostream>
#include <string>
// Required by for routine
#include <sys/types.h>
#include <unistd.h>
using namespace std;
int globalVariable = 2;
main()
{
string sIdentifier;
int iStackVariable = 20;
pid_t pID = vfork();
if (pID == 0) // child
{
// Code only executed by child process
sIdentifier = "Child Process: ";
globalVariable++;
iStackVariable++;
cout << "PROCESO NUMERO"<<getpid()<<sIdentifier;
// printf("Proceso hijo: PID %d - PPID %d\n", getpid(), getppid());
cout << " Global variable: " << globalVariable;
cout << " Stack variable: " << iStackVariable << endl;
return (0);
}
else if (pID < 0) // failed to fork
{
cerr << "Failed to fork" << endl;
return (1);
// Throw exception
}
else // parent
{
// Code only executed by parent process
sIdentifier = "Parent Process:";
}
// executed only by parent
cout << sIdentifier;
cout << " Global variable: " << globalVariable;
cout << " Stack variable: " << iStackVariable << endl;
return (0);
}
Is this of use ? Note the caveats surrounding modification of variables.
The vfork() function has the same effect as fork(), except that the behaviour is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit() or one of the exec family of functions.
If you vfork() both processes are sharing an address space. You should probably only use vfork() if you are going to exec another process pretty much immediately in the child. The reason the system call was created was to avoid the overhead of copying every page in the parent process's address space only to have all those mappings discarded when the child exec's. For your case, use fork() instead.