C++ fork(), multi-threading and OS's concepts - c++

Today, I wrote a small program in C++ like this:
pid_t pChild=0;
printf("Main process ID:%d\n",getpid());
pChild= fork();
printf("%d\n",pChild);
if (pChild!=0){
printf("Parent process ID:%d\n",getpid());
printf("Child process ID:%d\n",pChild);
}
else printf("Sorry! The child can not be created\n");
return 0;
And the output was like this
Main process ID: 3140
Sorry! The child can not be created
Parent process ID:3140
Child process ID:3141
And then, I wondered about the output.
I guessed the first getpid() of the child process didn't run because it read the same data with the getpid() from its parent; and this msg
Sorry! The child can not be created
It must be from the if statement of the child process. Correct me if I wrong...
But I still can't understand why the fork() function of the child's didn't run. Why it was blocked? Does it because they read the same pChild data (one of the fork() in child process and the other is main process's if-statement)?
Can anyone explain more detail about it? Thank you.

From the fork() documentation:
RETURN VALUE
Upon successful completion, fork() shall return 0 to the child process
and shall return the process ID of the child process to the parent process.
Your code assumes any zero return value is an error.
Continuing:
Both processes shall continue to execute from the fork() function.
Otherwise, -1 shall be returned to the parent process, no child
process shall be created, and errno shall be set to indicate the
error.
A -1 return value is an error indication.

Related

Kill all child processes that used exec, c++

I don't know if this is the best way but I have a random number of child processes who have beed execed and wanted to implement a way to kill them without using ctrl+c. I was thinking of keeping a set of their pids and then check that set whenever I want to kill them from the parent process.
The way I was trying to do it was something like this
set<pid_t> pids;
pid_t id = fork();
if(id == 0)
{
pids.insert(getpid());
execlp("./somewhere", "./somewhere", something.c_str(), NULL);
cout << "Didn't exec" << endl;
exit(0);
}
for(auto i : pids)
{
kill(i, something?)
}
I still don't quite know how to use the kill function or how pids work so I don't know if this will work in any way, I just did a simple project in c for college and though I could try something more complex in c++.
Anyways, the objective of this is to be able to have the parent process kill a single child process out of an undefined number of running child processes, or kill them all whenever the user writes quit
kill() on pid 0 sends the signal to all members of the calling process group:
If pid is 0, sig shall be sent to all processes (excluding an
unspecified set of system processes) whose process group ID is equal
to the process group ID of the sender, and for which the process has
permission to send a signal.
If you want to kill only certain processes (as seems to be your case) take a look to Grouping child processes with setpgid()

Can't kill all child processes using SIGTERM

My program has the following parent child layout:
int main() {
std::vector<pid_t> kids;
pid_t forkid = fork();
if (forkid == 0) {
//child process
pid_t fork2 = fork()
if (fork2 == 0) {
// child process
}else {
//parent
kids.push_back(fork2);
}
}else {
// code here
kids.push_back(forkid);
}
// Not killing the fork2 process - only the first process(forkid) is terminated
for (pid_t k : kids) {
int status;
kill(k, SIGTERM);
waitpid(k, &status, 0);
}
}
I am not able to kill the child process (fork2) - the first process gets terminated. The kids vector seems to only contain the process id of the first process. Never gets the pid of the child process.
What am I doing wrong here. Any help will be appreciated. Thanks.
std::vector<pid_t> kids;
pid_t forkid = fork();
fork() creates a complete duplicate image of the parent process as its child process. Emphasis on: duplicate.
This means that, for example, the child process has its very own kids vector, that has nothing to do, whatsoever, with the parent process's original kids vector.
Since this is the very first thing that happens in main, this is really no different than you running this executable twice, individually as two distinct and separate processes, instead of forking off a process. You can't expect the kids vector in one of the two processes to have any effect on the kids vector in the other one.
The first child process creates a 2nd child process, and also adds the 2nd child process's pid into its own kids vector. But that's just the first child process's kids vector.
The only process id that the original parent process's kids vector ends up having is the first child's process it, so that's all you get to SIGTERM.
Your options are:
Restructure your logic so that both child process get created by the parent process, so it, alone, puts their process ids into its kids vector.
Instead of using fork use multiple execution threads, and the same process. However, neither std::vector, nor any other C++ library container is thread safe. A massive pile of code will need to be written to properly synchronize the threads, in order for things to work themselves out correctly (not to mention that the analogue for the SIGTERM, with respect to multiple execution threads, needs to be invented in some way).
The simplest alternative is the first one.

What does the fork_rv return?

I know that fork() creates a duplicate process (clone) meaning two identical copies of address spaces are created - one for the parent and one for the child. This process becomes child process of the caller. However, I am confused as to what is inside fork_rv (see comment in code below)
include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
main()
{
int fork_rv;
printf("Before: my pid is %d\n",getpid());
fork_rv=fork();
if (fork_rv == -1)
perror("fork");
else if (fork_rv == 0)
printf ("I am the child. my pid=%d\n",getpid());
else
printf ("I am the parent. my child is %d\n",fork_rv); /* What is inside fork_rv What gets printed exactly? The address of the child?) */
}
Quoting from the Linux manual page for fork:
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.
While #Brian's answer is already correct, maybe explaining the logic behind these return values makes it easier to understand:
-1 for error should be clear.
0 as value for the child process makes sense because the child process can always get its own pid (getpid()) as well as the pid of its parent process (getppid()).
All values > 0 are the pid of the new child process that was created, returned to the parent process. Since a process can have multiple child processes, a 'get child pid' function is not possible: The pid of which child should it return? And with a 'get children pids' function that would return a list of all child processes pids, it would be cumbersome to find the pid of the latest, new child process.

Waiting in Background process in C program in Unix

Im trying to emulate shell through C program. In my program whenever I run any normal (foreground) commands it works fine. Also I have handled background process with commands ending with '&'. Now to handle this I have avoided the parent waiting for a child process.
The problem is whenever for the first time in my shell I run any background command(i.e ending in '&') then it works fine. But then after that each command(normal) doesnot terminate. I guess it waits for the previously opened process. How to rectify. Please you can ask questions so that i can make myself more clear to you. This is the snippet which is doing the above mentioned task.
child_id=fork();
if(child_id==0){
//logic fo creating command
int ret=execvp(subcomm[0],subcomm);
}
//Child will never come here if execvp executed successfully
if(proc_sate!='&'){
for(i=0;i<count_pipe+1;i++){
waitpid(0,&flag,0);
}
//something to add to make it not wait for other process in my scenario for second time
}
Here proc_state just determines whether it is background or foreground.It is just a character. count_pipe is just a variable holding number of pipes (e.g ls -l|wc|wc this contains 2 pipes). Dont worry this all is working fine.
waitpid(0, &flag, 0) waits for any child process whose process group ID is equal to that of your shell. So if you have not called setsid() after the fork() of the disconnected child process, the code above will wait for that too.
pid_t pid = fork();
if (pid == 0) { /* child process */
setsid(); /* Child creates new process group */
... /* redirections, etc */
execvp(...);
}

fork and exec many different processes, and obtain results from each one

I have managed to fork and exec a different program from within my app. I'm currently working on how to wait until the process called from exec returns a result through a pipe or stdout. However, can I have a group of processes using a single fork, or do I have to fork many times and call the same program again? Can I get a PID for each different process ? I want my app to call the same program I'm currently calling many times but with different parameters: I want a group of 8 processes of the same program running and returning results via pipes. Can someone please point me to the right direction please ? I've gone through the linux.die man pages, but they are quite spartan and cryptic in their description. Is there an ebook or pdf I can find for detailed information ? Thank you!
pid_t pID = fork();
if (pID == 0){
int proc = execl(BOLDAGENT,BOLDAGENT,"-u","2","-c","walkevo.xml",NULL);
std::cout << strerror(errno) << std::endl;
}
For example, how can I control by PID which child (according to the parameter xml file) has obtained which result (by pipe or stdout), and thus act accordingly? Do I have to encapsulate children processes in an object, and work from there, or can I group them altogether?
One Fork syscall make only one new process (one PID). You should organize some data structures (e.g. array of pids, array of parent's ends of pipes, etc), do 8 fork from main program (every child will do exec) and then wait for childs.
After each fork() it will return you a PID of child. You can store this pid and associated information like this:
#define MAX_CHILD=8
pid_t pids[MAX_CHILD];
int pipe_fd[MAX_CHILD];
for(int child=0;child<MAX_CHILD;child++) {
int pipe[2];
/* create a pipe; save one of pipe fd to the pipe_fd[child] */
int ret;
ret = fork();
if(ret) { /* parent */
/* close alien half of pipe */
pids[child] = ret; /* save the pid */
} else { /* child */
/* close alien half of pipe */
/* We are child #child, exec needed program */
exec(...);
/* here can be no more code in the child, as `exec` will not return if there is no error! */
}
}
/* there you can do a `select` to wait data from several pipes; select will give you number of fd with data waiting, you can find a pid from two arrays */
It's mind-bending at first, but you seem to grasp that, when you call fork( ):
the calling process (the "parent") is
essentially duplicated by the
operating system and the duplicate process
becomes the "child"
with a unique PID all its own;
the returned value from the fork( )
call is either: integer
0,1 meaning that the
program receiving the 0 return is the
"child"; or it is the non-zero integer PID
of that forked child; and
the new child process is entered into
the scheduling queue for execution.
The parent remains in the scheduling
queue and continues to execute as
before.
It is this ( 0 .xor. non-0 ) return from fork( ) that tells the program which role it's playing at this instant -- 0 returned, program is the child process; anything else returned, program is the parent process.
If the program playing the parent role wants many children, he has to fork( ) each one separately; there's no such thing as multiple children sharing a fork( ).
Intermediate results certainly can be sent via a pipe.
As for calling each child with different parameters, there's really nothing special to do: you can be sure that, when the child gets control, he will have (copies of) exactly the same variables as does the parent. So communicating parameters to the child is a matter of the parent's setting up variable values he wants the child to operate on; and then calling fork( ).
1 More accurately: fork( ) returns a value of type pid_t, which these days is identical to an integer on quite a few systems.
It's been a while since I've worked in C/C++, but a few points:
The Wikipedia fork-exec page provides a starting point to learn about forking and execing. Google is your friend here too.
As osgx's answer says, fork() can only give you one subprocess, so you'll have to call it 8 times to get 8 processes and then each one will have to exec the other program.
fork() returns the PID of the child process to the main process and 0 to the subprocess, so you should be able to do something like:
int pid = fork();
if (pid == 0) {
/* exec new program here */
} else {
/* continue with parent process stuff */
}