I need to create a certain number of concurrent child processes. I also want each child process to modify a global variable so the main parent process can print it in its last modified version. When I run the program below, the final value for 'k' will be 5, so the global variable does not change. If I remove the "exit(0)" part, then the global variable changes but this time the number of child processes created gets bigger.
Using fork(), how would I create an X number of child processes that can modify the data (global variables, local variables, etc) in the main parent process?
int k = 5; // global variable
int main(){
int i=0;
int status;
for(i = 0; i<5; i++){
if(fork() == 0){
printf("child %d %d\n", i, ++k);
sleep(5);
printf("done %d\n",i);
exit(0);
}
}
return 0;
}
As Kevin commented, what you really want is threads.
Doing IPC for this is overkill.
Look at the following link.
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
You cannot do this in this manner. Fork will create a new process, which will copy (or copy-on-write) the memory pages into the new process. That means that each of your child processes will get their own copy of "k", and each copy of "k" will only get incremented once.
To have all the processes communicate back to the "same" k variable, you need to perform some sort of interprocess communications.
Examples of good inter-process communications:
Have the parent process create a shared memory segment which stores the value of k. Have the children processes wait for an exclusive grab of the shared memory segment (via a parent process created mutex). When the child has the exclusive lock, have the child read the value of k and store the value of k + 1.
Create a per-process pipe between the parent an children processes. Have the parent read the pipe for a message indicating the desire to increment k. Have the parent process then increment k on the child's behalf.
Examples of poor inter-process communications:
Any solution which fails to ensure that changes in K are atomic (meaning that two contending children might both increment K to the same value). Such a lack of care would result in a value of K that appears to be incremented fewer times than the number of children processes, as the set values might look like (2, 3, 3, 4, 5). This means that file i/o is mostly useless, unless you create a framework around it that ensures atomic operations in locking the file for exclusive access.
Child processes cannot by default change anything in the parent's address space. You need shared memory for that, as well as a mutex mechanism to prevent race conditions.
Processes by definition can't modify resources of other processes (such as global vars, etc) directly. You want to use threads rather than processes for this. Look into pthread_create(3) or clone(2)
A child process gets a copy of parents address space. In other words, every child process has its own copy of global variables.
You need to put your variable in a shared memory mapping to allow all child processes and the parent process share the same variable.
Related
Consider this simple code:
int myvar = 0;
int main() {
if (fork()>0) {
myvar++;
} else {
// father do nothing
}
}
When child increments myvar, is the value shared with the father (like pthread)?
No and yes.
No, they are not shared in any way which is visible to the programmer; the processes can modify their own copies of the variables independently and they will change without any noticable effect on the other process(es) which are fork() parents, siblings or descendents.
But yes, the OS actually does share the pages initially, because fork implements copy-on-write which means that provided none of the processes modifies the pages, they are shared. This is, however, an optimisation which can be ignored.
If you wanted to have shared variables, put them in an anonymous shared mapping (see mmap()) in which case they really will get shared, with all the caveats which come with that.
fork()ing creates an exact copy of the parent process at the time of forking. However, after the fork() is completed, the child has a completely different existence, and will not report back to the parent.
In other words, no, the parent's global variables will not be altered by changes in the child.
After fork(), the entire process, including all global variables, is duplicated. The child is an exact replica of the parent, except that it has a different PID(Process Id), a different parent, and fork() returned 0. Global variables are still global within its own process. So the answer is no, global variables are not shared between processes after a call to fork().
No, since global variables are not shared between processes unless some IPC mechanism is implemented. The memory space will be copied. As a consequence, the global variable in both processes will have the same value inmediately after fork, but if one changes it, the other wont see it changed.
Threads on the other hand do share global variables.
I have an array of processes, and I have to implement all of them parallelly. As the number of processes depends on the size of the array, how do I carry out this question? I'm assuming I have to use fork() or threads but I am not sure how. And how do I return immediately after the process has been carried out? Thanks!
First let's get a few things straight:
fork() is on POSIX systems the system call to split one process into two. The child process will be indicated by a return code of 0, and the parent by The Pid of the child (returning immediately while the child may be created/executing/dying). Aside from that, the two are essentially identical, which means the child needs to carry out the specific sub-processing (usually by means of execve()ing) another binary), while the parent wait4()s the child. Another option is to not wait4(), but instead listen for SIGCHLD, sent when the child terminates.
Multiple threads all happen in the same process. Meaning that the sub processing is carried out by code blocks/functions in the same address space.
It's not clear from your question - so - If your array of processes is essentially an array of command lines, you use fork() and execve(), above. If it's an array of functions, use threads.
I have the code:
int a = 0;
if (fork() == 0) {
a = a + 1;
printf("%d \n", a);
} else {
a = a - 1;
printf("%d \n", a);
}
And I want to know whether or not this code will always print different values for the 2 prints?
Or if we will have context switch after the son process will add 1 and then the father process will do minus 1. In this case we will get same value. The thing is I'm not sure if the variable 'a' is duplicated and each process will have different copy of it (and then we will always get different values), or is shared (and then the situation I mentions can cause the same value to be printed twice)?
Thanks a lot!
A forked child doesn't share its address space with its parent. It gets a copy, although as an optimization, that copy may be a lazy, copy-on-write copy, which is what Linux does.
On Linux a forked child process will initially share its address space with its parent, but if it attempts to write anywhere, then (provided that write attempt is not a segmentation fault) Linux will redirect that write to a copy of the original page.
The fork() creates a child process by duplicating the calling process.
The process that invoked fork() is the parent process and the newly created process is the child process. The child process and the parent process run in separate memory spaces. But at the time of fork() both memory spaces have the same content.
There is concept called Copy-on-Write, which is an optimization where the page tables are set up so that the parent and child process start off sharing all of the same memory, and only the pages that are written to by either process are copied when needed. Which means both parent and child process share copy of the same data and as soon as either of them do a write, a copy is made and any change in the memory of one process is not visible in another's.
In the context of your program -
Yes, both parent and child process share a copy of variable a until its written by either of the process and then a copy is made. Any change in value of variable a done by either of the process (parent/child) will be in its own copy of a and that change is not visible to the other process.
Check this - Copy-on-write.
Take the following example:
int main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
ChildProcess();
else
ParentProcess();
}
So correct me if I am wrong, once fork() executes a child process is created. Now going by this answer fork() returns twice. That is once for the parent process and once for the child process.
Which means that two separate processes come into existence DURING the fork call and not after it ending.
Now I don't get it how it understands how to return 0 for the child process and the correct PID for the parent process.
This where it gets really confusing. This answer states that fork() works by copying the context information of the process and manually setting the return value to 0.
First am I right in saying that the return to any function is placed in a single register? Since in a single processor environment a process can call only one subroutine that returns only one value (correct me if I am wrong here).
Let's say I call a function foo() inside a routine and that function returns a value, that value will be stored in a register say BAR. Each time a function wants to return a value it will use a particular processor register. So if I am able to manually change the return value in the process block I am able to change the value returned to the function right?
So am I correct in thinking that is how fork() works?
How it works is largely irrelevant - as a developer working at a certain level (ie, coding to the UNIX APIs), you really only need to know that it works.
Having said that however, and recognising that curiosity or a need to understand at some depth is generally a good trait to have, there are any number of ways that this could be done.
First off, your contention that a function can only return one value is correct as far as it goes but you need to remember that, after the process split, there are actually two instances of the function running, one in each process. They're mostly independent of each other and can follow different code paths. The following diagram may help in understanding this:
Process 314159 | Process 271828
-------------- | --------------
runs for a bit |
calls fork |
| comes into existence
returns 271828 | returns 0
You can hopefully see there that a single instance of fork can only return one value (as per any other C function) but there are actually multiple instances running, which is why it's said to return multiple values in the documentation.
Here's one possibility on how it could work.
When the fork() function starts running, it stores the current process ID (PID).
Then, when it comes time to return, if the PID is the same as that stored, it's the parent. Otherwise it's the child. Pseudo-code follows:
def fork():
saved_pid = getpid()
# Magic here, returns PID of other process or -1 on failure.
other_pid = split_proc_into_two();
if other_pid == -1: # fork failed -> return -1
return -1
if saved_pid == getpid(): # pid same, parent -> return child PID
return other_pid
return 0 # pid changed, child, return zero
Note that there's a lot of magic in the split_proc_into_two() call and it almost certainly won't work that way at all under the covers(a). It's just to illustrate the concepts around it, which is basically:
get the original PID before the split, which will remain identical for both processes after they split.
do the split.
get the current PID after the split, which will be different in the two processes.
You may also want to take a look at this answer, it explains the fork/exec philosophy.
(a) It's almost certainly more complex than I've explained. For example, in MINIX, the call to fork ends up running in the kernel, which has access to the entire process tree.
It simply copies the parent process structure into a free slot for the child, along the lines of:
sptr = (char *) proc_addr (k1); // parent pointer
chld = (char *) proc_addr (k2); // child pointer
dptr = chld;
bytes = sizeof (struct proc); // bytes to copy
while (bytes--) // copy the structure
*dptr++ = *sptr++;
Then it makes slight modifications to the child structure to ensure it will be suitable, including the line:
chld->p_reg[RET_REG] = 0; // make sure child receives zero
So, basically identical to the scheme I posited, but using data modifications rather than code path selection to decide what to return to the caller - in other words, you'd see something like:
return rpc->p_reg[RET_REG];
at the end of fork() so that the correct value gets returned depending on whether it's the parent or child process.
In Linux fork() happens in kernel; the actual place is the _do_fork here. Simplified, the fork() system call could be something like
pid_t sys_fork() {
pid_t child = create_child_copy();
wait_for_child_to_start();
return child;
}
So in the kernel, fork() really returns once, into the parent process. However the kernel also creates the child process as a copy of the parent process; but instead of returning from an ordinary function, it would synthetically create a new kernel stack for the newly created thread of the child process; and then context-switch to that thread (and process); as the newly created process returns from the context switching function, it would make the child process' thread end up returning to user mode with 0 as the return value from fork().
Basically fork() in userland is just a thin wrapper returns the value that the kernel put onto its stack/into return register. The kernel sets up the new child process so that it returns 0 via this mechanism from its only thread; and the child pid is returned in the parent system call as any other return value from any system call such as read(2) would be.
You first need to know how multitasking works. It is not useful to understand all the details, but every process runs in some kind of a virtual machine controlled by the kernel: a process has its own memory, processor and registers, etc. There is mapping of these virtual objects onto the real ones (the magic is in the kernel), and there is some machinery that swap virtual contexts (processes) to physical machine as time pass.
Then, when the kernel forks a process (fork() is an entry to the kernel), and creates a copy of almost everything in the parent process to the child process, it is able to modify everything needed. One of these is the modification of the corresponding structures to return 0 for the child and the pid of the child in the parent from current call to fork.
Note: nether say "fork returns twice", a function call returns only once.
Just think about a cloning machine: you enter alone, but two persons exit, one is you and the other is your clone (very slightly different); while cloning the machine is able to set a name different than yours to the clone.
The fork system call creates a new process and copies a lot of state from the parent process. Things like the file descriptor table gets copied, the memory mappings and their contents, etc. That state is inside the kernel.
One of the things the kernel keeps track for every process are the values of registers this process needs to have restored at the return from a system call, trap, interrupt or context switch (most context switches happen on system calls or interrupts). Those registers are saved on a syscall/trap/interrupt and then restored when returning to userland. System calls return values by writing into that state. Which is what fork does. Parent fork gets one value, child process a different one.
Since the forked process is different from the parent process, the kernel could do anything to it. Give it any values in registers, give it any memory mappings. To actually make sure that almost everything except the return value is the same as in the parent process requires more effort.
For each running process, the kernel has a table of registers, to load back when a context switch is made. fork() is a system call; a special call that, when made, the process gets a context switch and the kernel code executing the call runs in a different (kernel) thread.
The value returned by system calls is placed in a special register (EAX in x86) that your application reads after the call. When the fork() call is made, the kernel makes a copy of the process, and in each table of registers of each process descriptor writes the appropiate value: 0, and the pid.
I'm using fork() in C to split up the work of running through local arrays, having each process run through half and then multiply the numbers at each point in the arrays and then set the product in a third array.
pid_t pid;
pid = fork();
if (pid == 0){
for (i=1; i<((SIZE/2)+1); i++)
{
output[i] = (one[i] * two[i]);
}
exit(0);
}
else{
wait(NULL);
for (i=((SIZE/2)+1); i<(SIZE+1); i++)
{
output[i] = one[i]*two[i];
}
}
However, when I print the product array after this segment of code i'm only receiving the section set by the parent process, i'm assuming this is because the child process is storing it's values elsewhere in memory which the parent is unable to pick up when printing the product array, but i'm not entirely sure. Thanks in advance for any help.
it seems that you have fork confused with threading.
Forking copies the whole process. Forking isn't like firing off a thread (well it is similar, but threads share the process memory, forking copies the process memory). Changes made after the fork aren't shared between parent or children. If you want to share memory between a parent and child on UNIX while using fork() you need to setup a shared memory segment and put that array within that memory. Lookup shared memory (shmget, smctl) if you want to stick with the fork semantics.
forking has its uses, but is an older, traditional multi-processing API that has in most cases been superseded by multithreading. Forking a new process is much more expensive than creating a new thread, even though fork is optimized on modern OSes that support it. Probably the most common use of fork() is to create a daemon (fork + parent exit) or to execute a command (pipe + fork + exec) as in the implementation of the popen() call.
If using C, you should look into the pthreads API or some other thread library that supports a system thread. Of course, looking at your intended task, you can still use fork, but once you get the hang of threads, it isn't any more complex than using fork with shared memory, unless the algorithm you are implementing is complex.
When you fork, the new child process gets a copy of the parent's address space. It is completely separate. If you need to communicate between parent and child, you will need to use pipes, shared memory, or such.
Note: in any modern Linux, the child's page table is pointing to all of the parent's pages, and both pages table's entries are marked "copy on write". Thus both processes are actually looking at the same physical memory. However, as soon as either process tries to write to a page of memory, it traps and then get's a private copy of the page to modify. From the processes' point of view, it is the same, except that the fork is a lot faster.