fork() flow in C - c

I am having a little trouble with understanding execution flow of fork(). My main question is that when fork() is called does the calling process pause execution flow, or continue execution? Here is an example of what I'm working on
for (i = 0; i < hosts; i++)
{
if (fork() == 0)
{
forward_data(client_sock, remote_sock[i]);
}
}
Here I use the fork() function to create separate processes that handle connections between remote hosts. The function forward_data() sends data from client_sock to remote_sock, and I am designing the program to send to multiple hosts at the same time.

fork() will duplicate the process and both processes (original and clone) will continue to execute from there, the only difference is that in the parent process, fork() will return the PID of the new process that was created (or -1 if error), while in the child process fork() will have returned 0.
It doesn't quite count as multithreading as once this split happens, the processes are no longer in the same virtual memory space.

First, as noted elsewhere, fork() makes a copy of the current process, and then both the new and the old process continue after the fork() returns -- the new process will see fork() return 0, the old process will see fork() return the pid of the new (child) process.
In what you've written, the original process will spawn hosts children, and each child will run forward_data(). If forward_data() returns, then each child will then spawn hosts - 1 grandchildren, who will in turn each spawn hosts - 2 further greatgrandchildren and so on.
Second, the short answer to the question "does the calling process pause execution flow, or continue execution?" is yes. The longer answer is that the calling process may or may not execute at the same time as the newly created process, you cannot tell and it may be different every time -- if you care, then you need to use some IPC mechanism to synchronise as required.
Third, since the question is tagged "multithreading", if the old process is running more than one pthread, then the new process inherits all the mutexes, conditions etc of the old process, in the state they were in when fork() was called. However, the new process has only one pthread, and that is a copy of the pthread in the old process which executed the fork().

Related

Wait for a group of processes, without a leader?

I have some code that forks/waits, but it also might end up using some third party code that may also fork/wait. To limit the amount of processes I fork, I want to wait for a process to exit, if too many have been forked already. If I wait for any process though, I might wait on a process that third party code then expects to be able to wait on, leaving that third party code with a failure result and no information on exit status. My own code will also not work right, since I'll end up with a negative amount of active processes, if I end up waiting for more processes than I fork.
I was going to try to keep my forking limited to a process group, so I could wait on that, but where do I get a special "my code" process group, to use in my blocking version of fork? I can't get third party code to set a special process group themselves, and I can't use any process group except for the pid of the process doing all these forks, which third party code will also use. I could use one of the child processes as the process group leader, but then when that child exits I'm hosed, since I'll have to wait on two process groups now, then three, and so on. Should I just realloc a growing array of process groups that still have child processes in them? I could fork a process that immediately exits, then use that "zombie" process as the process group leader, but then when I wait on any process in that group, it'll clean up the zombie process leaving me once again with no process group leader. I'd use setrusage to limit subprocesses, but then when fork fails from too many subprocesses, I have no way to wait for any of those subprocesses to exit before trying to fork again.
My best idea so far is a heap allocated growing list of lists of subprocesses, each with a possibly dead process group leader. Can you still wait on a process group if the leader has exited though? If the pids overflow and cycle around, and a new process happens to get that pid, will it just magically become the process group leader? Should I be using something with semaphores? Two processes with every fork, one to wait on the other then increment the semaphore? A heap allocated growing list of pids to wait for individually, just randomly guessing which pid will exit first? I have to keep my own custom "zombie process" table, right? So that I can "wait" for a process that's already been waited for and still get the exit status? Am I just forbidden from using third party code in any process that forks, and need to always use the code in child processes so the parent can't inadvertently wait on any internal forks?
What I ended up doing ...seems like it was effective. "No good solutions" etc. but what I did was:
process A forks process B, then process A just waits on B
process B sets its own process group to itself (B)
process B can have a special fork function then, that sets the process group to A after forking (A being the "grandparent" process)
any naive fork will just use the process group B
if this system uses itself, then B will fork C, and C's subprocesses will use B as a process group. So not even that will interfere with process group A
if B counts too many processes, it just waits on group A, to get any of (and only) the child processes that have been counted
One problem is that shells rely on process groups for killing a process tree. They won't kill any subprocesses that set a different process group. So I had to use the non-platform-specific prctl(PR_SET_PDEATHSIG, ...) to have subprocesses kill themselves when the parent process dies. And furthermore, because PDEATHSIG gives you the thread ID, not the process ID, I had to use PR_SET_CHILD_SUBREAPER on process B, so that anything getting a PDEATHSIG would get one for when B dies, but can ignore when the thread within B exits.
A platform independent way to do this might be just poll kill(getppid(), 0) before every fork, to see whether you should die rather than fork. Checking the return value of setpgid might work too, but I don't know if it forbids you from using process A as a process group, if A has died, the PID number has cycled around, and a totally unrelated process happened to get A's old PID.

Are my fork processes running parallel or executing one after another?

I am just going to post pseudo code,
but my question is I have a loop like such
for(i<n){
createfork();
if(child)
/*
Exit so I can control exact amount of forks
without children creating more children
*/
exit
}
void createfork(){
fork
//execute other methods
}
Does my fork create a process do what it is suppose to do and exit then create another process and repeat? And if so what are some ways around this, to get the processes running concurrently?
Your pseudocode is correct as written and does not need to be modified.
The processes are already executing in parallel, all six of them or however many you spawn. As written, the parent process does not wait for the children to finish before spawning more children. It calls fork(), checks if (child) (which is skipped), then immediately proceeds to the next for loop iteration and forks again.
Notably, there's no wait() call. If the parent were to call wait() or waitpid() to wait for each child to finish then that would introduce the serialism you're trying to avoid. But there is no such call, so you're good.
When a process successfully performs a POSIX fork(), that process and the new child process are initially both eligible to run. In that sense, they will run concurrently until one or the other blocks. Whether there will be any periods of time when both are executing machine instructions (on different processing units) depends at least on details of hardware capabilities, OS scheduling, the work each process is performing, and what other processes there are in the system and what they are doing.
The parent certainly does not, in general, automatically wait for the child to terminate before it proceeds with its own work (there is a family of functions to make it wait when you want that), nor does the child process automatically wait for any kind of signal from the parent. If the next thing the parent does is fork another child, then that will under many circumstances result in the parent running concurrently with both (all) children, in the sense described above.
I cannot speak to specifics of the behavior of your pseudocode, because it's pseudocode.

How to handle a fork error for a multithreaded process?

I am working on a multithreaded process that forks to execute another process. Sometimes, the fork may error if the execution file does not exist. Since this process has multiple threads running prior to fork I have a couple questions:
Are threads copied over to the forked process.
What is the best practice to handling an error from fork with a multithreaded process. For example:
/* in a multithreaded process */
pid = fork();
if(pid == 0)
{
execlp(filename, filename, NULL);
fprintf(stderr, "filename doesn't exist");
/* what do i do here if there's multiple threads running
from the fork? */
exit(-1);
}
Well, the fork doesn't error if the executable file doesn't exist. The exec errors in that case. But, to your actual question, POSIX states that fork creates a new process with a single thread, a copy of the thread that called fork. See here for details:
A process shall be created with a single thread. If a multi-threaded process calls fork(), the new process shall contain a replica of the calling thread and its entire address space, possibly including the states of mutexes and other resources.
Consequently, to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called.
So what you have is okay, if a little sparse :-)
A single thread will be running in the child and, if you cannot exec another program, log a message and exit.
And, in the rationale section, it explains why it was done that way:
There are two reasons why POSIX programmers call fork(). One reason is to create a new thread of control within the same program (which was originally only possible in POSIX by creating a new process); the other is to create a new process running a different program. In the latter case, the call to fork() is soon followed by a call to one of the exec functions.
The general problem with making fork() work in a multi-threaded world is what to do with all of the threads. There are two alternatives. One is to copy all of the threads into the new process. This causes the programmer or implementation to deal with threads that are suspended on system calls or that might be about to execute system calls that should not be executed in the new process. The other alternative is to copy only the thread that calls fork(). This creates the difficulty that the state of process-local resources is usually held in process memory. If a thread that is not calling fork() holds a resource, that resource is never released in the child process because the thread whose job it is to release the resource does not exist in the child process.
When a programmer is writing a multi-threaded program, the first described use of fork(), creating new threads in the same program, is provided by the pthread_create() function. The fork() function is thus used only to run new programs, and the effects of calling functions that require certain resources between the call to fork() and the call to an exec function are undefined.

Running/pausing child processes in C?

I'm running child processes in C and I want to pause and then run the same child process. Not really sure how to describe my problem in a better way since I'm new at this but here's a shot.
So I know that you can run a process after another process exits by using waitpid. But what if the process I'm waiting on doesn't exist at the creation of the process that does the waiting. So in this case, I'm thinking of pausing the process that does the waiting and when the process that is waited is created and then finishes, it would call on the process that does the waiting to run again. So how would you do this? Again, I'm not familiar with this, so I don't know if this is the proper way to do this.
edit: What I'm trying to do
I'm using child processes to run command via execvp() in parallel so if I have a sequence sleep 1; sleep 1;, the total sleep time will be 1 second. However there are cases where I try to parallel echo blah > file; cat < file; in which case I'm assuming cat reads the file after echo inputs blah into file. Therefore, I have to wait for echo to finish to do cat. There are more specifics to this, but generally assume that for any command with an output to a file must be waited on by any command that reads the file later in the script.
In Linux: You can set an alarm() before you waitpid() so you can wakeup after a certain number of seconds and waitpid() should return EINTR so you would know the situation and can kill the misbehaving one. Another way would be to use a mutex and having a block like this in the waiting process:
if (pthread_mutex_trylock(&mutex) {
sleep(some seconds);
if (pthread_mutex_trylock(&mutex) {
kill the process
}
}
and the process that is monitored:
ENTRY-POINT:
pthread_mutex_lock(&mutex);
do_stuff();
pthread_mutex_unlock(&mutex);
Any application (process) can only wait with waitpid() on its own direct children. It can't wait on grandchildren or more distant descendants, and it can wait on neither siblings nor ancestors nor on unrelated processes.
If your application is single-threaded, you can't wait on a process that will be created after the waitpid() call starts because there is nothing to do the necessary fork() to create the child.
In a multi-threaded process, you could have one thread waiting for dying children and another thread could be creating the children. For example, you could then have the waitpid() call in thread 1 start at time T0, then have thread 2 create a child at T1 (T1 > T0), and then the child dies at T2, and the waitpid() would pick up the corpse of the child at T3, even though the child was created after the waitpid() started.
Your higher level problem is probably not completely tractable. You can't tell which processes are accessing a given file just by inspecting the command lines in a 'shell script'. You can see those that probably are using it (because the file name appears on the command line); but there may be other processes that have the name hardwired into them and you can't see that by inspecting the command line.

What is the purpose of fork()?

In many programs and man pages of Linux, I have seen code using fork(). Why do we need to use fork() and what is its purpose?
fork() is how you create new processes in Unix. When you call fork, you're creating a copy of your own process that has its own address space. This allows multiple tasks to run independently of one another as though they each had the full memory of the machine to themselves.
Here are some example usages of fork:
Your shell uses fork to run the programs you invoke from the command line.
Web servers like apache use fork to create multiple server processes, each of which handles requests in its own address space. If one dies or leaks memory, others are unaffected, so it functions as a mechanism for fault tolerance.
Google Chrome uses fork to handle each page within a separate process. This will prevent client-side code on one page from bringing your whole browser down.
fork is used to spawn processes in some parallel programs (like those written using MPI). Note this is different from using threads, which don't have their own address space and exist within a process.
Scripting languages use fork indirectly to start child processes. For example, every time you use a command like subprocess.Popen in Python, you fork a child process and read its output. This enables programs to work together.
Typical usage of fork in a shell might look something like this:
int child_process_id = fork();
if (child_process_id) {
// Fork returns a valid pid in the parent process. Parent executes this.
// wait for the child process to complete
waitpid(child_process_id, ...); // omitted extra args for brevity
// child process finished!
} else {
// Fork returns 0 in the child process. Child executes this.
// new argv array for the child process
const char *argv[] = {"arg1", "arg2", "arg3", NULL};
// now start executing some other program
exec("/path/to/a/program", argv);
}
The shell spawns a child process using exec and waits for it to complete, then continues with its own execution. Note that you don't have to use fork this way. You can always spawn off lots of child processes, as a parallel program might do, and each might run a program concurrently. Basically, any time you're creating new processes in a Unix system, you're using fork(). For the Windows equivalent, take a look at CreateProcess.
If you want more examples and a longer explanation, Wikipedia has a decent summary. And here are some slides here on how processes, threads, and concurrency work in modern operating systems.
fork() is how Unix create new processes. At the point you called fork(), your process is cloned, and two different processes continue the execution from there. One of them, the child, will have fork() return 0. The other, the parent, will have fork() return the PID (process ID) of the child.
For example, if you type the following in a shell, the shell program will call fork(), and then execute the command you passed (telnetd, in this case) in the child, while the parent will display the prompt again, as well as a message indicating the PID of the background process.
$ telnetd &
As for the reason you create new processes, that's how your operating system can do many things at the same time. It's why you can run a program and, while it is running, switch to another window and do something else.
fork() is used to create child process. When a fork() function is called, a new process will be spawned and the fork() function call will return a different value for the child and the parent.
If the return value is 0, you know you're the child process and if the return value is a number (which happens to be the child process id), you know you're the parent. (and if it's a negative number, the fork was failed and no child process was created)
http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html
fork() is basically used to create a child process for the process in which you are calling this function. Whenever you call a fork(), it returns a zero for the child id.
pid=fork()
if pid==0
//this is the child process
else if pid!=0
//this is the parent process
by this you can provide different actions for the parent and the child and make use of multithreading feature.
fork() will create a new child process identical to the parent. So everything you run in the code after that will be run by both processes — very useful if you have for instance a server, and you want to handle multiple requests.
System call fork() is used to create processes. It takes no arguments and returns a process ID. The purpose of fork() is to create a new process, which becomes the child process of the caller. After a new child process is created, both processes will execute the next instruction following the fork() system call. Therefore, we have to distinguish the parent from the child. This can be done by testing the returned value of fork():
If fork() returns a negative value, the creation of a child process was unsuccessful.
fork() returns a zero to the newly created child process.
fork() returns a positive value, the process ID of the child process, to the parent. The returned process ID is of type pid_t defined in sys/types.h. Normally, the process ID is an integer. Moreover, a process can use function getpid() to retrieve the process ID assigned to this process.
Therefore, after the system call to fork(), a simple test can tell which process is the child. Please note that Unix will make an exact copy of the parent's address space and give it to the child. Therefore, the parent and child processes have separate address spaces.
Let us understand it with an example to make the above points clear. This example does not distinguish parent and the child processes.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#define MAX_COUNT 200
#define BUF_SIZE 100
void main(void)
{
pid_t pid;
int i;
char buf[BUF_SIZE];
fork();
pid = getpid();
for (i = 1; i <= MAX_COUNT; i++) {
sprintf(buf, "This line is from pid %d, value = %d\n", pid, i);
write(1, buf, strlen(buf));
}
}
Suppose the above program executes up to the point of the call to fork().
If the call to fork() is executed successfully, Unix will make two identical copies of address spaces, one for the parent and the other for the child.
Both processes will start their execution at the next statement following the fork() call. In this case, both processes will start their execution at the assignment
pid = .....;
Both processes start their execution right after the system call fork(). Since both processes have identical but separate address spaces, those variables initialized before the fork() call have the same values in both address spaces. Since every process has its own address space, any modifications will be independent of the others. In other words, if the parent changes the value of its variable, the modification will only affect the variable in the parent process's address space. Other address spaces created by fork() calls will not be affected even though they have identical variable names.
What is the reason of using write rather than printf? It is because printf() is "buffered," meaning printf() will group the output of a process together. While buffering the output for the parent process, the child may also use printf to print out some information, which will also be buffered. As a result, since the output will not be send to screen immediately, you may not get the right order of the expected result. Worse, the output from the two processes may be mixed in strange ways. To overcome this problem, you may consider to use the "unbuffered" write.
If you run this program, you might see the following on the screen:
................
This line is from pid 3456, value 13
This line is from pid 3456, value 14
................
This line is from pid 3456, value 20
This line is from pid 4617, value 100
This line is from pid 4617, value 101
................
This line is from pid 3456, value 21
This line is from pid 3456, value 22
................
Process ID 3456 may be the one assigned to the parent or the child. Due to the fact that these processes are run concurrently, their output lines are intermixed in a rather unpredictable way. Moreover, the order of these lines are determined by the CPU scheduler. Hence, if you run this program again, you may get a totally different result.
You probably don't need to use fork in day-to-day programming if you are writing applications.
Even if you do want your program to start another program to do some task, there are other simpler interfaces which use fork behind the scenes, such as "system" in C and perl.
For example, if you wanted your application to launch another program such as bc to do some calculation for you, you might use 'system' to run it. System does a 'fork' to create a new process, then an 'exec' to turn that process into bc. Once bc completes, system returns control to your program.
You can also run other programs asynchronously, but I can't remember how.
If you are writing servers, shells, viruses or operating systems, you are more likely to want to use fork.
Multiprocessing is central to computing. For example, your IE or Firefox can create a process to download a file for you while you are still browsing the internet. Or, while you are printing out a document in a word processor, you can still look at different pages and still do some editing with it.
Fork creates new processes. Without fork you would have a unix system that could only run init.
Fork() is used to create new processes as every body has written.
Here is my code that creates processes in the form of binary tree.......It will ask to scan the number of levels upto which you want to create processes in binary tree
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
int main()
{
int t1,t2,p,i,n,ab;
p=getpid();
printf("enter the number of levels\n");fflush(stdout);
scanf("%d",&n);
printf("root %d\n",p);fflush(stdout);
for(i=1;i<n;i++)
{
t1=fork();
if(t1!=0)
t2=fork();
if(t1!=0 && t2!=0)
break;
printf("child pid %d parent pid %d\n",getpid(),getppid());fflush(stdout);
}
waitpid(t1,&ab,0);
waitpid(t2,&ab,0);
return 0;
}
OUTPUT
enter the number of levels
3
root 20665
child pid 20670 parent pid 20665
child pid 20669 parent pid 20665
child pid 20672 parent pid 20670
child pid 20671 parent pid 20670
child pid 20674 parent pid 20669
child pid 20673 parent pid 20669
First one needs to understand what is fork () system call. Let me explain
fork() system call creates the exact duplicate of parent process, It makes the duplicate of parent stack, heap, initialized data, uninitialized data and share the code in read-only mode with parent process.
Fork system call copies the memory on the copy-on-write basis, means child makes in virtual memory page when there is requirement of copying.
Now Purpose of fork():
Fork() can be used at the place where there is division of work like a server has to handle multiple clients, So parent has to accept the connection on regular basis, So server does fork for each client to perform read-write.
fork() is used to spawn a child process. Typically it's used in similar sorts of situations as threading, but there are differences. Unlike threads, fork() creates whole seperate processes, which means that the child and the parent while they are direct copies of each other at the point that fork() is called, they are completely seperate, neither can access the other's memory space (without going to the normal troubles you go to access another program's memory).
fork() is still used by some server applications, mostly ones that run as root on a *NIX machine that drop permissions before processing user requests. There are some other usecases still, but mostly people have moved to multithreading now.
The rationale behind fork() versus just having an exec() function to initiate a new process is explained in an answer to a similar question on the unix stack exchange.
Essentially, since fork copies the current process, all of the various possible options for a process are established by default, so the programmer does not have supply them.
In the Windows operating system, by contrast, programmers have to use the CreateProcess function which is MUCH more complicated and requires populating a multifarious structure to define the parameters of the new process.
So, to sum up, the reason for forking (versus exec'ing) is simplicity in creating new processes.
Fork() system call use to create a child process. It is exact duplicate of parent process. Fork copies stack section, heap section, data section, environment variable, command line arguments from parent.
refer: http://man7.org/linux/man-pages/man2/fork.2.html
Fork() was created as a way to create another process with shared a copy of memory state to the parent. It works the way it does because it was the most minimal change possible to get good threading capabilities in time-slicing mainframe systems that previously lacked this capability. Additionally, programs needed remarkably little modification to become multi-process, fork() could simply be added in the appropriate locations, which is rather elegant. Basically, fork() was the path of least resistance.
Originally it actually had to copy the entire parent process' memory space. With the advent of virtual memory, it has been hacked and changed to be more efficient, with copy-on-write mechanisms avoiding the need to actual copy any memory.
However, modern systems now allow the creation of actual threads, which simply share the parent process' actual heap. With modern multi-threading programming paradigms and more advanced languages, it's questionable whether fork() provides any real benefit, since fork() actually prevents processes from communicating through memory directly, and forces them to use slower message passing mechanisms.

Resources