C fork() and pointers interaction [duplicate] - c

In this C program, data is not being shared between process i.e. parent and child process. child has it's own data and parent has it's own data but pointer is showing the same address for both processes. How it is being done on background? Does fork generates copies of same data? if so then we have the same pointer's address for both processes. Or is it due to the statically allocated data that is being copied for each process and the data is independent for each process? I want to know how it is being done?
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
//Static Array
int X[] = {1,2,3,4,5};
int i, status;
//The fork call
int pid = fork();
if(pid == 0) //Child process
{
//Child process modifies Array
for(i=0; i<5; i++)
X[i] = 5-i;
//Child prints Array
printf("Child Array:\t");
for(i=0; i<5; i++)
printf("%d\t", X[i]);
printf("\nArray ptr = %p\n", X);
}
else //Parent process
{
// Wait for the child to terminate and let
// it modify and print the array
waitpid(-1, &status, 0);
//Parent prints Array
printf("Parent Array:\t");
for(i=0; i<5; i++)
printf("%d\t", X[i]);
printf("\nArray ptr = %p\n", X);
}
return 0;
}
Here is the output of the program.
1 Child Array: 5 4 3 2 1
2 Array ptr = 0x7fff06c9f670
3 Parent Array: 1 2 3 4 5
4 Array ptr = 0x7fff06c9f670
When child process modifies array it should have also modified the data of parent process. What is going on in background?

When you fork a new process the new child process is a copy of the parent process. That's why pointers etc. are equal. Due to the wonders of virtual memory two processes can have the same memory map, but still be using different memory.

fork creates exact copy of the parent process memory image (exception see in man page). This is called Copy On Write(COW) fork. Upto time child only read data, both parent and child have same copy of data but when child write, a new copy is generated and then both child and parent have different copyies for their own data

fork() creates a copy of the calling process, including all the memory allocated to it.
Each process has its own address space and the values of pointers are within context of that address space. So printing the address of some variable in the original process will give the same output as printing that address in the spawned process.
However, as far as the operating system is concerned, the addresses are not equal. The operating system takes care of ensuring each process has the illusion of its own memory.
There are means of sharing memory between processes (i.e. what one process writes to the shared memory, the other one sees). However, that is not what happens by default, and still happens with the help of the host operating system.

Related

A struct for each child process and accessing the members

So I'm forking a couple of child processes and each of them is supposed to take a line that I've read from a file and do operations on them.
What I have is a struct containing the lines like :
struct query {
char lines[LINESIZE];
};
and I have an array of structs. So each struct serves to one child process.
This is how I forked my child processes :
for(i=0; i<5; i++) {
n = fork();
}
And say I have five structs to serve for each of these processes.
struct query query[5];
So First processes takes query[0].lines and do some operations on it, second process gets query[1].lines and does the same operations on it and so on ...
Should I use pipe to pass values between processes? I feel like there's a much simpler solution to this but my lack of practice and knowledge in C is really slowing me down.
I suppose you're trying to spawn 5 processes, but in the code that you posted you'll end up creating way more than 5 processes, in fact in:
for(i = 0; i < 5; ++i) {
n = fork();
}
when i = 0 you'll fork a process, since the forked process is an exact copy of the parent it will continue in the for loop, so at that point you'll have two processes each one having i = 1 and forking each one a new process, then you'll have at this point 4 processes, when the loop is complete you have created 160 processes.
Allocating and initializing the array "query" before the forking it is perfectly fine what you have to fix is the spawning. The fork() call returns 0 in the child process, the process id of the child to the parent process or -1 if there was a error. Knowing if the current process is the parent or the child we can continue or break out of the loop and do the computation:
for(i = 0; i < 5; ++i) {
if(fork() == 0) {
/* child process */
process_query(query[i]);
exit();
}
}

Read-Write shared memory

I have a program in which i have a parent process and i want to create 3 children processes.
I also have created 2 shared memories (IN, OUT) and 1 semaphore for each shared memory.
The idea is:
The parent process has 3 integers and has to write in shared memory (IN) one of these integers. Then one of the children processes reads it, does some calculations and writes something in shared memory (OUT) from where the parent reads the result. Then the parent process adds the next integer to the shared memory and so on..
This is part of my code where i try to implement the first part (write-read from shared memory IN):
// create and attach shared memory
memidIN = shmget(...);
memidOUT= shmget(...);
pointerIN = (...) shmat(...);
pointerOUT = (...) shmat(...);
// create and init semaphores
semIN = semget(...);
semOUT = semget(...);
semctl(semIN, ...); // initialize both to 1
semctl(semOUT, ...);
for (i = 0; i < children; ++i)
{
pid = fork();
if (pid)
{
// parent process code
down sem_IN
write in shmIN
up sem_IN
}
else if (pid == 0)
{
// Children processes code
down sem_IN
read from shmIN
up sem_IN
exit(0);
}
else
//ERROR
}
// dont die until childrens die
for( j = 0; j < children; j++)
wait(&status);
The question is, how can i be sure that the children processes read the correct value? I mean if the parent process writes 5 then one process should take it, do something, write something in OUT. Then the parent should write another value, lets say 10.
In my program 5 could be read by the children processes 2 or more times.
Should i use a mutex semaphore to make sure that the children processes read the correct value and to make sure that the parent process updates the value when one of the children has read it?
Any ideas?
So, you can arrange data in you IN shared memory by this way:
int Number;
bool Number_IsRead; // Initialized by 'true'.
When you need to pass a Number, you should do
Number_IsRead = false;
Child should check Number_IsRead before reading Number.
When Number has read, child should assign true to Number_IsRead.
If you have 3 children who need to read Number, you should create 3 flags (bool Number_IsRead[3]).
Also you must use semaphores when you changing Number or Number_IsRead.
P.S. In general it is not a good idea to use shared memory instead of message queues (msgget/msgctl/msgsnd/msgrcv/etc.).

how memory area is shared between processes [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
How memory is shared in following scenarios?
Between Parent and child Processes
Between two irrelevant Processes
In which part of the physical memory does the shared memory (or) any other IPC used for communicating between processes exists?
Here it the program with explanation of Memory management between Parent and Child Process..
/*
SHARING MEMORY BETWEEN PROCESSES
In this example, we show how two processes can share a common
portion of the memory. Recall that when a process forks, the
new child process has an identical copy of the variables of
the parent process. After fork the parent and child can update
their own copies of the variables in their own way, since they
dont actually share the variable. Here we show how they can
share memory, so that when one updates it, the other can see
the change.
*/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h> /* This file is necessary for using shared
memory constructs
*/
main()
{
int shmid. status;
int *a, *b;
int i;
/*
The operating system keeps track of the set of shared memory
segments. In order to acquire shared memory, we must first
request the shared memory from the OS using the shmget()
system call. The second parameter specifies the number of
bytes of memory requested. shmget() returns a shared memory
identifier (SHMID) which is an integer. Refer to the online
man pages for details on the other two parameters of shmget()
*/
shmid = shmget(IPC_PRIVATE, 2*sizeof(int), 0777|IPC_CREAT);
/* We request an array of two integers */
/*
After forking, the parent and child must "attach" the shared
memory to its local data segment. This is done by the shmat()
system call. shmat() takes the SHMID of the shared memory
segment as input parameter and returns the address at which
the segment has been attached. Thus shmat() returns a char
pointer.
*/
if (fork() == 0) {
/* Child Process */
/* shmat() returns a char pointer which is typecast here
to int and the address is stored in the int pointer b. */
b = (int *) shmat(shmid, 0, 0);
for( i=0; i< 10; i++) {
sleep(1);
printf("\t\t\t Child reads: %d,%d\n",b[0],b[1]);
}
/* each process should "detach" itself from the
shared memory after it is used */
shmdt(b);
}
else {
/* Parent Process */
/* shmat() returns a char pointer which is typecast here
to int and the address is stored in the int pointer a.
Thus the memory locations a[0] and a[1] of the parent
are the same as the memory locations b[0] and b[1] of
the parent, since the memory is shared.
*/
a = (int *) shmat(shmid, 0, 0);
a[0] = 0; a[1] = 1;
for( i=0; i< 10; i++) {
sleep(1);
a[0] = a[0] + a[1];
a[1] = a[0] + a[1];
printf("Parent writes: %d,%d\n",a[0],a[1]);
}
wait(&status);
/* each process should "detach" itself from the
shared memory after it is used */
shmdt(a);
/* Child has exited, so parent process should delete
the cretaed shared memory. Unlike attach and detach,
which is to be done for each process separately,
deleting the shared memory has to be done by only
one process after making sure that noone else
will be using it
*/
shmctl(shmid, IPC_RMID, 0);
}
}
/*
POINTS TO NOTE:
In this case we find that the child reads all the values written
by the parent. Also the child does not print the same values
again.
1. Modify the sleep in the child process to sleep(2). What
happens now?
2. Restore the sleep in the child process to sleep(1) and modify
the sleep in the parent process to sleep(2). What happens now?
Thus we see that when the writer is faster than the reader, then
the reader may miss some of the values written into the shared
memory. Similarly, when the reader is faster than the writer, then
the reader may read the same values more than once. Perfect
i /*
SHARING MEMORY BETWEEN PROCESSES
In this example, we show how two processes can share a common
portion of the memory. Recall that when a process forks, the
new child process has an identical copy of the variables of
the parent process. After fork the parent and child can update
their own copies of the variables in their own way, since they
dont actually share the variable. Here we show how they can
share memory, so that when one updates it, the other can see
the change.
*/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h> /* This file is necessary for using shared
memory constructs
*/
main()
{
int shmid. status;
int *a, *b;
int i;
/*
The operating system keeps track of the set of shared memory
segments. In order to acquire shared memory, we must first
request the shared memory from the OS using the shmget()
system call. The second parameter specifies the number of
bytes of memory requested. shmget() returns a shared memory
identifier (SHMID) which is an integer. Refer to the online
man pages for details on the other two parameters of shmget()
*/
shmid = shmget(IPC_PRIVATE, 2*sizeof(int), 0777|IPC_CREAT);
/* We request an array of two integers */
/*
After forking, the parent and child must "attach" the shared
memory to its local data segment. This is done by the shmat()
system call. shmat() takes the SHMID of the shared memory
segment as input parameter and returns the address at which
the segment has been attached. Thus shmat() returns a char
pointer.
*/
if (fork() == 0) {
/* Child Process */
/* shmat() returns a char pointer which is typecast here
to int and the address is stored in the int pointer b. */
b = (int *) shmat(shmid, 0, 0);
for( i=0; i< 10; i++) {
sleep(1);
printf("\t\t\t Child reads: %d,%d\n",b[0],b[1]);
}
/* each process should "detach" itself from the
shared memory after it is used */
shmdt(b);
}
else {
/* Parent Process */
/* shmat() returns a char pointer which is typecast here
to int and the address is stored in the int pointer a.
Thus the memory locations a[0] and a[1] of the parent
are the same as the memory locations b[0] and b[1] of
the parent, since the memory is shared.
*/
a = (int *) shmat(shmid, 0, 0);
a[0] = 0; a[1] = 1;
for( i=0; i< 10; i++) {
sleep(1);
a[0] = a[0] + a[1];
a[1] = a[0] + a[1];
printf("Parent writes: %d,%d\n",a[0],a[1]);
}
wait(&status);
/* each process should "detach" itself from the
shared memory after it is used */
shmdt(a);
/* Child has exited, so parent process should delete
the cretaed shared memory. Unlike attach and detach,
which is to be done for each process separately,
deleting the shared memory has to be done by only
one process after making sure that noone else
will be using it
*/
shmctl(shmid, IPC_RMID, 0);
}
}
/*
POINTS TO NOTE:
In this case we find that the child reads all the values written
by the parent. Also the child does not print the same values
again.
1. Modify the sleep in the child process to sleep(2). What
happens now?
2. Restore the sleep in the child process to sleep(1) and modify
the sleep in the parent process to sleep(2). What happens now?
Thus we see that when the writer is faster than the reader, then
the reader may miss some of the values written into the shared
memory. Similarly, when the reader is faster than the writer, then
the reader may read the same values more than once. Perfect
inter-process communication requires synchronization between the
reader and the writer. You can use semaphores to do this.
Further note that "sleep" is not a synchronization construct.
We use "sleep" to model some amount of computation which may
exist in the process in a real world application.
Also, we have called the different shared memory related
functions such as shmget, shmat, shmdt, and shmctl, assuming
that they always succeed and never fail. This is done to
keep this proram simple. In practice, you should always check for
the return values from this function and exit if there is
an error.
*/nter-process communication requires synchronization between the
reader and the writer. You can use semaphores to do this.
Further note that "sleep" is not a synchronization construct.
We use "sleep" to model some amount of computation which may
exist in the process in a real world application.
Also, we have called the different shared memory related
functions such as shmget, shmat, shmdt, and shmctl, assuming
that they always succeed and never fail. This is done to
keep this proram simple. In practice, you should always check for
the return values from this function and exit if there is
an error.
*/

pthreads/ wait(&status)

I read a book that gives the next example:
int value=0
int thread_func(int id) {
int temp;
temp=value+id;
printf("Thread%d value: %d", id, temp);
value=temp;
}
int main() {
int fork_id, status, i;
pthread_t tids[3];
fork_id=fork();
if (fork_id == 0) {
for (i=1; i≤3; i++)
pthread_create(&tids[i-1], NULL, thread_func, i);
for (i=0; i≤2; i++)
pthread_join(tids+i, &status);
printf("Second process value: %d", value);
}
else {
wait(&status);
printf("First process value: %d", value)
}
I don't understand two main things:
As I read, the only value that the line has in printf("First process value: %d", value) is 0.
But why? wait(&status) is wait until the child process is terminate. In out case, it will terminate only after all the joins would done. meaning, when the value is 6.
Second, in the line printf("Second process value: %d", value);, the vaule can be from 1 to 6. This is also strange, because we have the join instruction.
The answers to your questions:
The value will be 0 in the parent process because when the fork occurs the address space of the parent is duplicated (along with the variable value) in the child process. Hence, although value is changed in the child, this change is not reflected in the parent as they are different variables.
Since there is no synchronization involved, there is no way to know in which order the variable value is changed by the three child threads. Specifically, each thread has a local temp variable with a different value, which is then copied in the global value variable, but there is no way to know in which order the threads will overwrite value with temp here: value = temp;. Hence, its value can vary between executions.
Because when you fork, you get a brand new process with its own memory, which means that changes to a variable in one process won't show up in another. Threads, on the other hand, share their memory, which means that changes to variables in a threaded program show up in all threads.
The value is incremented by the child process, so the parent process will show its value as 0.
if(fork_id == 0){
......
......
}
is executed by the child which spawned threads.
And child process has different copy of memory. so increasing value in child does not mean the same for parent.
And threads have access to global values.

C: printf (with fork())

In the next code:
int i = 1;
fork();
i=i*2;
fork();
i=i*2;
fork();
i=i*2;
printf("%d\n", i);
Why 8,8,8,8,8,8,8,8 is printed, and not 1,2,2,4,4,8,8,8? fork() duplicate the process, and print the i before each fork. What I miss?
Given the code shown, you should be seeing eight lots of 6 (you wrote i = i + 2; instead of i = i * 2; for the last computation.
Since each process follows the same code path, each process will produce the same result.
To get the result you expected, you'd have to track whether each fork() yielded the parent or child process:
int i = 1;
if (fork())
{
i=i*2;
if (fork())
{
i=i*2;
if (fork())
i=i*2; // + --> *
}
}
printf(|%d\n", i);
I'm assuming there are no problems with the fork() operation. It is also interesting to note that you could invert any or all of the conditions and end up with the same result.
Because fork continues to execute the code as it goes downwards. So each of the processes will run through the i = i * 2 each time as they spawn off more children. Making it what you get and not what you expected (i.e. it doesn't jump to the end of the block once forked).
Info on fork: http://www.csl.mtu.edu/cs4411/www/NOTES/process/fork/create.html
Each new process gets a copy of the stack of the parent, so immediately after calling fork(), both parent and child have the same value for i -- but they don't have the same stack, just a copy... so changing i's value in one process has no effect on the other.
If you want two parallel pieces of code to share the same memory, either use threads (and memory that's in the heap, not on the stack), or use an explicit shared memory region.

Resources