Chinaunix首页 | 论坛 | 博客
  • 博客访问: 189293
  • 博文数量: 71
  • 博客积分: 2990
  • 博客等级: 少校
  • 技术积分: 705
  • 用 户 组: 普通用户
  • 注册时间: 2005-03-29 14:04
文章分类

全部博文(71)

文章存档

2011年(1)

2009年(1)

2007年(6)

2006年(42)

2005年(21)

我的朋友

分类: C/C++

2005-12-12 09:41:22

fork()会产生一个与父程序相同的子程序,唯一不同之处在於其process id(pid)。
如果我们要撰写守护程序,或是例如网路伺服器,需要多个行程来同时提供多个连线,可以利用fork()来产生多个相同的进程。

函数声明:
pid_t fork(void);
pid_t vfork(void);

返回值:
-1 :
失败。
  0 :
子程序。

>0 :
将子程序的process id传回给父程序。

Linuxfork()vfork()是相同的东西。

范例一: fork.c

在这个范例中,我们示范fork()的标准用法。
#include
#include
#include

void main(void)
{
  pid_t pid;

  printf("hello ");
  pid = fork();

  switch (pid) {
    case -1: printf("failure! "); break;
    case  0: printf("I am child! "); break;
    default: printf("my child is %d ",pid); break;
  }
  for (;;) { /* do something here */ }
}

编译:
gcc -o ex1 fork.c

执行结果:

./ex1 &
hello
my child is 8650
I am child!

我们可以见到,使用fork(),可将一个程式分岐成两个。在分歧之前的程式码只执行一次。

检验行程:
ps | grep ex1
 8649  p0 R    0:40 ./ex1
 8650  p0 R    0:40 ./ex1

8649是父程序的pid8650则为子程序的pid
您会需要用到"killall ex1"来杀掉两个行程。

 

范例二: daemon.c
UNIX中,我们一般都利用fork(),来实作所谓的"守护神程式",也就是DOS中所谓的"常驻程式"。一般的技巧是将父程序结束,而子程序便成为"守护神"
这个范例中,示范一般标准的daemon写法。

#include
#include
#include

void main(void)
{
  pid_t pid;

  pid = fork();

  if (pid>0) {
    printf("daemon on duty! ");
    exit(0);
  } else
  if (pid<0) {
    printf("Can't fork! ");
    exit(-1);
  }

  for (;;) {
    printf("I am the daemon! ");
    sleep(3);
    /* do something your own here */
  }

}

编译:
gcc -o ex2 daemon.c
执行结果
:
./ex2
daemon on duty!
I am the daemon!
接下来每三秒钟,都会出现一个"I am the daemon!"的讯息,这表示您的程式已经"长驻"在系统中了。

检验行程:
ps | grep ex2
8753  p0 S    0:00 ./ex2

注意到在范例一中,我们下的指令为"./ex1 &",而在范例二中为"./ex2",没有"&"符号。

范例三: lock.c
许多的时候,我们希望"守护神"在系统中只有一个,这时候会需要用到pid lock的技巧。如果您注意到/var/run目录中的内容,您会发现到有许多的*.pid档,观看其内容都是一些数字,这些数字其实就是该行程的pid
#include
#include
#include

void main(void)
{
  FILE *fp;
  pid_t pid;

  if (access("/var/run/lock.pid",R_OK)==0) {
    printf("Existing a copy of this daemon! ");
    exit(1);
  }

  pid = fork();

  if (pid>0) {
    printf("daemon on duty! ");

    fp = fopen("/var/run/lock.pid","wt");
    fprintf(fp,"%d",pid);
    fclose(fp);

    exit(0);
  } else
  if (pid<0) {
    printf("Can't fork! ");
    exit(-1);
  }
 
   for (;;) {
    printf("I am the daemon! ");
    sleep(3);
  }
}

编译:
gcc -o ex3 lock.c
执行:
./ex3
daemon on duty!
I am the daemon!

再执行一次
./ex3

Existing a copy of this daemon!

这时如果您将该行程杀掉,并重新执行:
killall ex3
./ex3

Existing a copy of this daemon!

您会发现daemon无法再度长驻,因为/var/run/lock.pid并没有因为行程被杀掉而删除掉。一般来说,开机後的启动Script,会将/var/run中所有内容自动清除,以避免这个问题的发生。如果您想要在行程被杀掉时,将/var/run/lock.pid也一并删除,那麽您需要利用signal来处理这件事。

您可手动删除该档案,daemon便可再度执行。
rm /var/run/lock.pid

 

范例四: children.c
如果您正在写伺服器,您可能会需要复制出许多的子行程,用以提供同时多人的服务,这时可利用fork(),一次复制出多个子行程。最佳的例子为Apache WWW Server
#include
#include
#include

#define MAX_CHILD 9

void main(void)
{
  pid_t pid;
  int  n;

  printf("hello ");

  n = 0;
  do {

    pid = fork();
    n++;

    switch (pid) {
      case -1:
        printf("failure! ");
        exit(-1);
      break;
      case  0:
        printf("I am child %d! ",n);
      break;
      default:
        printf("my child is %d ",pid); break;
    }
  } while (pid!=0&&n<="" />

  if (pid>0) exit(0);

  for (;;) { /* do something here */ }
}

编译:
gcc -o ex4 children.c
执行结果:

./ex4
hello
my child is 8863
I am child 1!
my child is 8864
I am child 2!
my child is 8865
I am child 3!
my child is 8866
I am child 4!
my child is 8867
I am child 5!
my child is 8868
I am child 6!
my child is 8869
I am child 7!
my child is 8870
I am child 8!
my child is 8871
I am child 9!

检验行程:
ps | grep ex4
 8863  p0 R    0:12 ./ex4
 8864  p0 R    0:12 ./ex4
 8865  p0 R    0:12 ./ex4
 8866  p0 R    0:12 ./ex4
 8867  p0 R    0:12 ./ex4
 8868  p0 R    0:12 ./ex4
 8869  p0 R    0:11 ./ex4
 8870  p0 R    0:12 ./ex4
 8871  p0 R    0:12 ./ex4

阅读(1325) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~