开发者

Forking, Signals and how they interact with global variables in C

I am trying to understand how fork()/Linux Kernel deals with global variables.

Given code:

#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include <sys/types.h>

pid_t pid;
int counter = 2;
void handler1(int sig)
{
 counter = counter - 1;
 printf("%d", counter);
 exit(0);
}
int main()
{
    signal(SIGUSR1, handler1); //Install Handler
    printf("%d", counter);     //Print Parent global variable
    pid = fork( );             //Fork(), child pid = 0, parent's pid = positive int.
    if (pid == 0)              //Parent skips this, child goes into infinite loop
    {
      while(1) {}; // simulate doing some work
    }
    kill(pid, SIGUSR1);        //While child is the loop, parents calls to terminate the child. 
                               //Child will stop the inf开发者_如何学Cinite loop, and will not proceed any 
                               //Will it call handler1 ???

    wait(NULL);                //Wait for child to be ripped
                               //Will it call handler1 second time ???
    counter = counter + 1;     //This will surely increment global variable
    printf("%d", counter);
    exit(0);
}

The output is 2123 How does Unix/Linux kernel deals with global variables after fork() and signal handlers are called ??? Do they get shared between child & parent ?

Another issues I have with this code, is how kill() & wait() will deal with global variables and what set will they use - parent's or child's ?? And will they call signal handler ???

Thanks !


The child gets an independent copy of the global variables. The two copies are not shared.


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, a different parent, and fork() returned 0.

A signal handler in the child will use the child's independent copy of the global variable.

The reason you're seeing 2 printed twice is that you haven't flushed standard output after printing it. This is what happens:

  • counter is equal to 2.
  • Parent process executes printf("%d", counter);, which puts "2" into the stdout output buffer, but does not flush it. No output appears yet.
  • fork() is called, which duplicates the process. There are now two copies of the counter variable, and both are set to 2. There are also two instances of the stdout output buffer, both of which contain the string "2". No output appears yet.
  • The parent sends SIGUSR1 to the child, and blocks on wait().
  • The child executes handler1(), which decrements the child's copy of counter to 1, and puts "1" into the child's stdout output buffer (which now contains "21").
  • The child executes exit(0), which as a side-effect flushes stdout. The output "21" appears now, written by the child, and the child exits.
  • wait() returns in the parent process. The parent increments its copy of counter to 3, and then prints "3" into its stdout output buffer (which now contains "23").
  • The parent executes exit(0), which as a side-effect flushes stdout. The output "23" appears now, and the parent exits.

If you put fflush(stdout); before the fork(), the 2 will only be printed once, and the output will be "213". It is good practice to flush all buffered output streams before calling fork().


fork creates a copy of the process in its current state. Nothing is shared except explicitly-mapped shared memory resources (anonymous shared maps, shared file maps, sysv shared memory blocks, and POSIX shared memory blocks).

You should also be aware that while the new process has its own copy of the file descriptor table, these file descriptors refer to the same "open file descriptions" in the kernel. They share a current seek position, among other things.

For further details, see:

http://www.opengroup.org/onlinepubs/9699919799/functions/fork.html

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜