I understand that both parent and child in fork() are two separated processes, but I was trying to understand the behavior of a static variable when it's declared and initialized in the child. Consider this code please:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
static int z = 99;
void main(){
int x=99;
int pid;
pid = fork();
switch(pid){
case -1: printf("fork failed.");break;
case 0: printf("I am the Child[PID=%d].\n",getpid());
static int y=99;
x++;y++;z++;
printf("x=%d, y=%d, z=%d\n",x,y,z);break;
default: wait(NULL);
//int y = 99;
printf("Child has finished. I am the parent[PID=%d].\n",getpid());
printf("x=%d, y=%d, z=%d\n",x,y,z);
}
}
Output:
Why in parent printf statement the value of y is 99? although that the parent waited for the child to finish, and in the child the value of y is changed to 100 "y++" after it was set to 99.
This is because y exists in two separate processes, i.e. two separate virtual address spaces. Changing one process won't affect the other process.
Compare this with threads, where threads share the same process, i.e. the same virtual address space, change will be seen by all threads.
Static variables are initialized at load time (compile time), not at run time. In the fork(), the memory image is copied, including these initialized static vaiables. The child performs the increment, the parent not.
Related
I am learning about multi process and know that when using fork() child process is created, and the child obtains copies of the parent’s stack, data, heap, and text segments.
So why this code below does not print two "hello"?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
static int idata = 111; /* Allocated in data segment */
int main(int argc, char *argv[])
{
int istack = 222; /* Allocated in stack segment */
pid_t childPid;
idata *= 2;
istack *= 2;
printf("hello\n");
switch (childPid = fork()) {
case -1:
printf("fork fail\n");
exit(0);
case 0:
idata *= 3;
istack *= 3;
break;
default:
sleep(3); // Give child a chance to execute
break;
}
/* Both parent and child come here */
printf("PID=%ld %s idata=%d istack=%d\n", (long) getpid(),
(childPid == 0) ? "(child) " : "(parent)", idata, istack);
exit(0);
}
The result is
hello
PID=591 (child) idata=666 istack=1332
PID=590 (parent) idata=222 istack=444
why this code does not print two "hello"?
printf("hello\n"); happens before fork().
When the output is a terminal, stdout is line-buffered by default, it outputs 1 hello because stdout gets flushed on \n.
When the output is redirected into a file or a pipe, stdout is block-buffered by default, it outputs 2 hellos because both the parent and child processes have hello buffered and the buffers get flushed on exit().
you're making printf("hello\n"); before the call to the fork() function .
Trace the program flow. First there is only one process executing this program. This process prints "hello". Next, there is a fork system call inside the switch statement. Now there are two processes, parent and child. The child is a clone of the parent. Everything, except the process id, is the same for both. Even the next instruction to be executed is the same for both. Both, the parent and child execute the switch statement next. The child never had a chance to print "hello".
I want to calculate the factorial with Shared memory and fork()parent and child processes.My problem is child process doesn't seems to work, I want to give a number from parent to child and after the child passes the result of factorial to the parent. But the result is same with the number I gave.
I was asked to use snprintf() orspritnf()or itoa() and atoi() in order to pass the variable to each process.
I reached the following:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <sys/shm.h>
int main(int argc , char *argv[])
{
int shmid,fid,status,x;
char *shm;
char *s;
int i,y,c;
key_t key=1990;
//create shared memory
shmid=shmget(1990,300,IPC_CREAT|0666);
fid=fork();
shm=shmat(shmid,NULL,0);
if(fid>0)//parent process
{
wait(&status);
s=shm;
printf("enter a number:");
scanf("%d",&x);
sprintf(s,"%d",x);//convert int to string
printf("factorial of number:%d is:%s\n",x,s);//result
shmdt(shm);
shmctl(shmid,IPC_RMID,0);
}else if(fid==0)//child process
{
shm=shmat(shmid,NULL,0);
c=atoi(s);//conver string to int
// calculate factorial
for(i=1;i<=c;i++)
{
y *=i;
}
return y;
sprintf(s,"%d",y);
shmdt(shm);
}
return 0;
}
You have:
if(fid>0)//parent process
{
wait(&status);
The first thing the parent process does is wait for the child to die. Only then does it ask for the number that should be the input to the calculation. This isn't going to work well.
You need the parent to ask for the number, write it into shared memory, and tell the child via some (other) IPC mechanism that the number is ready. The child should then wake up, read the number, do the calculation, and write the answer, then notify the parent it is done simply by exiting. Meanwhile, the parent can now wait for the child to complete, and then reads the answer from the shared memory.
Were it my code, I'd do the shmat() before calling fork(). As written, the child uses shmat() twice (once just after the fork(), once in the else if (fid == 0) code. That's not orthodox.
It's odd to create the key_t key = 1990; and then not use it. I don't see status and x being used either.
As a way of calculating factorials, this is preposterous. As an exercise in IPC and inter-process synchronization, it is a nice simple example.
Remember, 32-bit integers can only store values up to 12! while 64-bit integers can only store values up to 20!, so it is usually sensible just to create a table of factorials — or just calculate them on the fly. Or you need to use floating-point arithmetic; it takes a while to get out their range (somewhere less than 200!, IIRC).
I supposed that my program should work like this:
1) initializing unnamed semaphore with value = 0
the second value for sem_init(..) is 1 so as it said in MAN the semaphore is shared between processes
2) creating child, child waits until semaphore value becomes 1
parent process increases the value of semaphore so the child should exit now
but it doesn't exit really, so that is the problem
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
pid_t child;
void child_proc(sem_t* sem) {
sem_wait(sem);
printf("OK\n");
}
void parent_proc(sem_t* sem) {
sem_post(sem);
sleep(2);
int status;
waitpid(child, &status, 0);
}
int main(int argc, char* argv[]) {
sem_t sem;
sem_init(&sem, 1, 0);
child = fork();
if (0 == child) {
child_proc(&sem);
return 0;
}
parent_proc(&sem);
return 0;
}
The problem is that both processes have a local (not shared) copy of the semaphore structure and changes in one process won't reflect to the other process.
As the man page also says, if you want to share semaphores across processes, not only do you need to pass a non-zero value to the second argument of sem_init, but the sem_t structure also needs to exist in an area of shared memory. In your example program, it exists on the stack, which is not shared.
You can have shared memory by using a common file mapping (with mmap) or with shm_open, notably.
I have to create a program that:
ask for a number
create a child process (using vfork)
calculate the square root (in the child process)
show the square root from the parent process
Here is my code
#include <stdio.h>
#include <sys/types.h>
#include <math.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
double n=0;
printf("Number: "); //ask number
scanf("%d", &n);
pid_t pid = vfork(); //create child process
if (pid==0)//if child process
{
printf("Child process started\n");
n = sqrt(n);//calculate square root
}
else//parent process
{
printf("Returnning to parent process\n");
printf("Square Root: %d",n);
}
return 0;
}
But my code doesnt work, can anyone help me?
Why would you expect it to work? Doing anything but exec or _exit after vfork results in explicitly undefined behavior. See:
vfork() system call
And some further discussion of the horrors of vfork:
http://ewontfix.com/7/
http://www.openwall.com/lists/musl/2012/12/31/16
In case it's interesting, here is a list of possible problems with your program (manifestations of the UB):
printf in the child could horribly corrupt the parent's stdio state.
n could be stored permanently in a register, in which case there's no way the parent could see the changes made by the child
The compiler can see that n is uninitialized in the else branch, so it need not generate any code to read it at all (this branch unconditionally invoked UB by accessing an object whose value is indeterminate).
You're calculating the square root in the child, but trying to print it in the parent. The parent has no idea what the square root is. If you want the parent to print the square root, then you'll need to communicate that value from the child back to the parent process somehow. It seems more likely that you're supposed to print the square root in the child process.
int main(int argc, char **argv) { int n=0;
pid_t pid = vfork(); //create child process
if (pid==0)//if child process
{
printf("Child process started\n");
scanf("%d",&n);
n = sqrt(n);//calculate square root
_exit(23);
}
else//parent process
{
printf("Returnning to parent process\n");
printf("Square Root: %ld",n);
}
return 0; }
I have studied that during a fork, the data and code segment of the parent process gets duplicated into the child process.
Kindly see the program below.
int main()
{
int a = 5;
pid_t pid;
pid = fork();
if(pid == 0)
{
printf("In child a = %d",a);
}
else
{
printf("In parent a = %d",a);
}
return 0;
}
Here a is in the stack segment of parent process as it is declared inside the function, main(). The child process should only get copy of the code and data segment of the parent process and not the stack during fork(). But when I run the program, I can see that the child process is able to access the variable 'a' also. Thats means somehow the stack of parent process is also copied into the child process.
Kindly tell me the reason for this and correct me if my understanding is wrong.
You should check the docs again. fork creates an "exact copy of the calling process". Admittedly, there are a lot of exceptions, but the stack is not one of them.
Also, if the stack wasn't duplicated, the very common idiom (also used in your code) of checking the return value (almost always a stack variable) from fork would fail. There wouldn't be a stack position for pid unless the stack (including stack pointer) was duplicated.
That isn't a good test - as Matthew has pointed out, fork() gives you an exact copy of the parent process, including the stack (else the child would be unable to return from this function).
A better test is to modify 'a' in the parent and observe it in the child, like this:
#include <stdio.h>
#include <unistd.h>
int main()
{
int a = 5;
pid_t pid;
pid = fork();
if (pid == 0)
{
sleep(5);
printf("In child a = %d\n",a);
}
else
{
a++;
printf("In parent a = %d\n",a);
}
return 0;
}
and the result is correct:
pandora:~/tmp$ cc -o x x.c
pandora:~/tmp$ ./x
In parent a = 6
pandora:~/tmp$ In child a = 5