LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 4156|回复: 6

多进程(fork)与多线程(pthread)之试验总结报告(待续)

[复制链接]
发表于 2007-8-15 09:48:18 | 显示全部楼层 |阅读模式
一、前言
学会使用多进程(fork)好久了,但由于一直没有在工作中使用,因此好多细节的东西都没有详细研究。现将其。。。

二、环境

  • 软件环境
    1. root@yxm:~/c++/test# cat /proc/version
    2. Linux version 2.6.16.27 (root@yxm) (gcc version 4.0.3) #1 SMP Sun Jan 28 01:47:24 CST 2007
    3. root@yxm:~/c++/test# gcc --version
    4. gcc (GCC) 4.0.3
    5. Copyright (C) 2006 Free Software Foundation, Inc.
    6. 本程序是自由软件;请参看源代码的版权声明。本软件没有任何担保;
    7. 包括没有适销性和适用性担保。
    8. root@yxm:~/c++/test#      
    复制代码

  • 硬件环境
    联想笔记本,旭日AD125系列
    PM1.73G,512M(DDRII533)x2,60G硬盘。



三、参考信息

http://www.linuxsir.cn/bbs/showthread.php?t=197428
man 2 fork
man 2 signal

四、实验步骤

“欲要善其事,必先利其器”。开始前先阅读了下fork的manpage。

  1. root@yxm:~# man 2 fork
  2. Reformatting fork(2), please wait...
  3. FORK(2)                  Linux Programmer's Manual                  FORK(2)

  4. NAME
  5.        fork - create a child process

  6. SYNOPSIS
  7.        #include <sys/types.h>
  8.        #include <unistd.h>

  9.        pid_t fork(void);

  10. DESCRIPTION
  11.        fork()  creates a child process that differs from the parent process
  12.        only in its PID and PPID, and in the fact that resource utilizations
  13.        are set to 0.  File locks and pending signals are not inherited.

  14.        Under Linux, fork() is implemented using copy-on-write pages, so the
  15.        only penalty that it incurs is  the  time  and  memory  required  to
  16.        duplicate  the  parent's  page  tables,  and to create a unique task
  17.        structure for the child.

  18. RETURN VALUE
  19.        On success, the PID of the child process is returned in the parent's
  20.        thread  of  execution,  and a 0 is returned in the child's thread of
  21.        execution.  On failure, a -1 will be returned in the  parent's  con-
  22.        text, no child process will be created, and errno will be set appro-
  23.        priately.

  24. ERRORS
  25.        EAGAIN fork() cannot allocate sufficient memory to copy the parent's
  26.               page tables and allocate a task structure for the child.

  27.        EAGAIN It  was  not  possible  to  create  a new process because the
  28.               caller's RLIMIT_NPROC resource  limit  was  encountered.   To
  29.               exceed   this   limit,  the  process  must  have  either  the
  30.               CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capability.

  31.        ENOMEM fork() failed to allocate  the  necessary  kernel  structures
  32.               because memory is tight.

  33. CONFORMING TO
  34.        The fork() call conforms to SVr4, SVID, POSIX, X/OPEN, 4.3BSD.

  35. EXAMPLE
  36.        See pipe(2) and wait(2).

  37. SEE ALSO
  38.        clone(2),  execve(2),  setrlimit(2),  unshare(2), vfork(2), wait(2),
  39.        capabilities(7)

  40. Linux 2.6.6                      2004-05-27                         FORK(2)
  41. Manual page fork(2) line 15/55 (END)
复制代码

由上可以看出,要在自己的代码中使用fork函数,首先要引用两个头文件
#include <sys/types.h>
#include <unistd.h>

如此,先写代码如下:

  1. /*
  2. forksignal.c
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>

  8. int main()
  9. {
  10.         pid_t pid;

  11.         pid = fork();

  12.         if (pid > 0)
  13.         {
  14.                 printf("这句由父进程执行!\n");
  15.         }
  16.         else
  17.         {
  18.                 printf("这句由子进程执行!\n");
  19.         }

  20.         return 0;
  21. }

复制代码

编译执行结果如下:

  1. root@yxm:~/c++/test# cc forksignal.c -o forksignal
  2. root@yxm:~/c++/test# ./forksignal
  3. 这句由子进程执行!
  4. 这句由父进程执行!
  5. root@yxm:~/c++/test# ./forksignal
  6. 这句由子进程执行!
  7. 这句由父进程执行!
  8. root@yxm:~/c++/test# ./forksignal
  9. 这句由子进程执行!
  10. 这句由父进程执行!
  11. root@yxm:~/c++/test#
复制代码

PS:我执行过多次,发觉子进程总是比父进程执行的快。我也想到了一些原因,但还不成熟,大家先讨论一下。
进一步修改源代码,如下:

  1. /*
  2. forksignal.c
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>

  8. int main()
  9. {
  10.         pid_t pid;
  11.         int i;

  12.         pid = fork();
  13.         for (i = 0; i < 10; ++i)
  14.         {
  15.                 if (pid > 0)
  16.                 {
  17.                         printf("%d: 这句由父进程执行!\n", i);
  18.                 }
  19.                 else
  20.                 {
  21.                         printf("%d: 这句由子进程执行!\n", i);
  22.                 }
  23.         }

  24.         return 0;
  25. }

复制代码

编译执行

  1. root@yxm:~/c++/test# cc forksignal.c -o forksignal
  2. root@yxm:~/c++/test# ./forksignal
  3. 0: 这句由子进程执行!
  4. 1: 这句由子进程执行!
  5. 2: 这句由子进程执行!
  6. 3: 这句由子进程执行!
  7. 4: 这句由子进程执行!
  8. 5: 这句由子进程执行!
  9. 6: 这句由子进程执行!
  10. 7: 这句由子进程执行!
  11. 8: 这句由子进程执行!
  12. 9: 这句由子进程执行!
  13. 0: 这句由父进程执行!
  14. 1: 这句由父进程执行!
  15. 2: 这句由父进程执行!
  16. 3: 这句由父进程执行!
  17. 4: 这句由父进程执行!
  18. 5: 这句由父进程执行!
  19. 6: 这句由父进程执行!
  20. 7: 这句由父进程执行!
  21. 8: 这句由父进程执行!
  22. 9: 这句由父进程执行![color="black"][/color]
  23. root@yxm:~/c++/test#
复制代码

由此产生疑问,rwimn兄在《Linux进程管理的一些问题,及其验证(献给正在学操作系统的同学们)》一文中讲到的“四、参考程序”的运行结果
五、运行结果
1、bca,bac, abc ,……都有可能。
2、parent…
son…
daughter..
daughter..
或 parent…
son…
parent…
daughter…等

为什么我这儿不是?记忆中,我以前第一次接触fork时的试验也产生了如rwimn兄所说的结果,对此我也深信不疑,可我现在的实验结果确实不一样,多次运行都是如此,strace与ltrace命令我的机器上没装。于是,继续实验中。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2007-8-15 10:51:41 | 显示全部楼层
我这里测试大部分时候都是子进程先运行,但是这也是没有保证的。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-8-15 11:37:01 | 显示全部楼层
我猜测,出现前面的效果可能是计算机速度太快的原因造成的,于是修改代码如下:

  1. /*
  2. forksignal.c
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>

  8. int main()
  9. {
  10.         pid_t pid;
  11.         int i;

  12.         pid = fork();

  13.         signal(17, ss17);
  14.         signal(16, ss16);

  15.         for (i = 0; i < 10; ++i)
  16.         {
  17.                 if (pid > 0)
  18.                 {
  19.                         printf("%d: 这句由父进程执行!\n", i);
  20.                         sleep(1);
  21.                 }
  22.                 else
  23.                         printf("%d: 这句由子进程执行!\n", i);
  24.                         sleep(1);
  25.                 }
  26.         }

  27.         return 0;
  28. }
复制代码

执行结果:

  1. root@yxm:~/c++/test# ./forksignal
  2. 0: 这句由子进程执行!
  3. 0: 这句由父进程执行!
  4. 1: 这句由子进程执行!
  5. 1: 这句由父进程执行!
  6. 2: 这句由子进程执行!
  7. 2: 这句由父进程执行!
  8. 3: 这句由子进程执行!
  9. 3: 这句由父进程执行!
  10. 4: 这句由子进程执行!
  11. 4: 这句由父进程执行!
  12. 5: 这句由子进程执行!
  13. 5: 这句由父进程执行!
  14. 6: 这句由子进程执行!
  15. 6: 这句由父进程执行!
  16. 7: 这句由子进程执行!
  17. 7: 这句由父进程执行!
  18. 8: 这句由子进程执行!
  19. 8: 这句由父进程执行!
  20. 9: 这句由子进程执行!
  21. 9: 这句由父进程执行!
  22. root@yxm:~/c++/test#
复制代码

现在我认为我的猜测是正确的,不知大家认为然否。

附:

  1. root@yxm:~# man 3 sleep
  2. Reformatting sleep(3), please wait...
  3. SLEEP(3)                 Linux Programmer's Manual                 SLEEP(3)

  4. NAME
  5.        sleep - Sleep for the specified number of seconds

  6. SYNOPSIS
  7.        #include <unistd.h>

  8.        unsigned int sleep(unsigned int seconds);

  9. DESCRIPTION
  10.        sleep()  makes  the current process sleep until seconds seconds have
  11.        elapsed or a signal arrives which is not ignored.

  12. RETURN VALUE
  13.        Zero if the requested time has elapsed, or  the  number  of  seconds
  14.        left to sleep.

  15. CONFORMING TO
  16.        POSIX.1

  17. BUGS
  18.        sleep()  may  be  implemented using SIGALRM; mixing calls to alarm()
  19.        and sleep() is a bad idea.

  20.        Using longjmp() from a signal handler or modifying the  handling  of
  21.        SIGALRM while sleeping will cause undefined results.

  22. SEE ALSO
  23.        alarm(2), signal(2)

  24. GNU                              1993-04-07                        SLEEP(3)
  25. Manual page sleep(3) line 1/36 (END)
复制代码


继续修改代码如下:

  1. /*
  2. forksignal.c
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>

  8. int main()
  9. {
  10.         pid_t pid;
  11.         int i;

  12.         pid = fork();

  13.         signal(17, ss17);
  14.         signal(16, ss16);

  15.         for (i = 0; i < 10; ++i)
  16.         {
  17.                 if (pid > 0)
  18.                 {
  19.                         printf("%d: 这句由父进程执行!\n", i);
  20.                         sleep(1);
  21.                 }
  22.                 else
  23.                         printf("%d: 这句由子进程执行!\n", i);
  24.                         sleep(1);
  25.                 }
  26.         }

  27.         return 0;
  28. }
复制代码

执行结果:

  1. root@yxm:~/c++/test# cc forksignal.c -o forksignal
  2. root@yxm:~/c++/test# ./forksignal
  3. 0: 这句由子进程执行!
  4. 0: 这句由父进程执行!
  5. 1: 这句由父进程执行!
  6. 2: 这句由父进程执行!
  7. 3: 这句由父进程执行!
  8. 4: 这句由父进程执行!
  9. 5: 这句由父进程执行!
  10. 6: 这句由父进程执行!
  11. 7: 这句由父进程执行!
  12. 8: 这句由父进程执行!
  13. 9: 这句由父进程执行!
  14. root@yxm:~/c++/test# 1: 这句由子进程执行!      [i][color="DarkOrchid"] 注:由此以下信息隔1秒出现一行[/color][/i]
  15. 2: 这句由子进程执行!
  16. 3: 这句由子进程执行!
  17. 4: 这句由子进程执行!
  18. 5: 这句由子进程执行!
  19. 6: 这句由子进程执行!
  20. 7: 这句由子进程执行!
  21. 8: 这句由子进程执行!
  22. 9: 这句由子进程执行!
复制代码

程序启动后,子进程输出首先被执行,输出了一行信息“0: 这句由子进程执行!”,然后休眠1秒,在此1秒时间内,父进行10次循环全部完成,并退出,所以回到了shell的命令提示符“root@yxm:~/c++/test# ”。最后子进程慢慢执行完剩余操作。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-8-15 13:39:32 | 显示全部楼层

一个不干实事儿的守护进程

根据以上实验结果写了一个“不干实事儿”的守护进程,代码如下:

  1. /*
  2. deamon.c
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <sys/types.h>
  7. #include <unistd.h>

  8. int main()
  9. {
  10.         pid_t pid;

  11.         pid = fork();

  12.         if (pid > 0) return 0;

  13.         while(1)
  14.         {
  15.                 sleep(1);
  16.         }
  17.         return 0;
  18. }
复制代码

执行

  1. root@yxm:~/c++/test# cc deamon.c -o deamon
  2. root@yxm:~/c++/test# ./deamon
  3. root@yxm:~/c++/test# ps
  4.   PID TTY          TIME CMD
  5. 2269 pts/6    00:00:00 bash
  6. 3261 pts/6    00:00:00 deamon
  7. 3262 pts/6    00:00:00 ps
  8. root@yxm:~/c++/test#     
复制代码

可以看到进程号为“3261”的程序已经在后台运行。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-8-15 14:15:05 | 显示全部楼层

向子进程发信号

如下代码:

  1. /*
  2. forksignal2.c
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>
  8. #include <signal.h>

  9. int isWorking = 1;

  10. void parent_fork(pid_t pid)
  11. {
  12.         while(isWorking)
  13.         {
  14.                 printf("0. 退出\n");
  15.                 printf("1. 向子进程发信号\n");
  16.                 printf("2. 退出子进程\n");
  17.                 printf("请输入您的选择: \n");
  18.                 scanf("%d", &isWorking);
  19.                 switch(isWorking)
  20.                 {
  21.                 case 0:
  22.                         break;
  23.                 case 1:
  24.                         kill(pid, 16);
  25.                 case 2:
  26.                         if (pid == 0)
  27.                         {
  28.                                 printf("子进程不存在\n");
  29.                                 break;
  30.                         }
  31.                         kill(pid, 17);
  32.                         pid = 0;
  33.                         break;
  34.                 default:
  35.                         isWorking = 0;
  36.                 }
  37.         }
  38. }

  39. void sub_fork_working()
  40. {
  41.         printf("别烦我,正忙着呢!\n");
  42. }

  43. void sub_fork_quit()
  44. {
  45.         isWorking = 0;
  46. }

  47. void sub_fork()
  48. {
  49.         signal(16, sub_fork_working);
  50.         signal(17, sub_fork_quit);

  51.         while(isWorking)
  52.         {
  53.                 sleep(1);
  54.         }
  55. }

  56. int main()
  57. {
  58.         pid_t pid;

  59.         pid = fork();

  60.         if (pid > 0)
  61.                 parent_fork(pid);
  62.         else
  63.                 sub_fork();

  64.         return 0;
  65. }
复制代码

设计本意,父进程向子进程发送信号16则子进程回显一信息后继续运行,父进程向子进程发送信号17则子进程退出。运行结果如下:

  1. root@yxm:~/c++/test# cc forksignal2.c -o forksignal2
  2. root@yxm:~/c++/test# ./forksignal2
  3. 0. 退出
  4. 1. 向子进程发信号
  5. 2. 退出子进程
  6. 请输入您的选择:
  7. 1
  8. 别烦我,正忙着呢!
  9. 0. 退出
  10. 1. 向子进程发信号
  11. 2. 退出子进程
  12. 请输入您的选择:
  13. 1
  14. 栈失效
  15. root@yxm:~/c++/test# ./forksignal2
  16. 0. 退出
  17. 1. 向子进程发信号
  18. 2. 退出子进程
  19. 请输入您的选择:
  20. 2
  21. 0. 退出
  22. 1. 向子进程发信号
  23. 2. 退出子进程
  24. 请输入您的选择:
  25. 2
  26. 子进程不存在
  27. 0. 退出
  28. 1. 向子进程发信号
  29. 2. 退出子进程
  30. 请输入您的选择:
  31. 0
  32. root@yxm:~/c++/test#
复制代码

回头检查源文件,发现有逻辑错误,修改后代码如下:

  1. /*
  2. forksignal2.c
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>
  8. #include <signal.h>

  9. int isWorking = 1;

  10. void parent_fork(pid_t pid)
  11. {
  12.         while(isWorking)
  13.         {
  14.                 printf("0. 退出\n");
  15.                 printf("1. 向子进程发信号\n");
  16.                 printf("2. 退出子进程\n");
  17.                 printf("请输入您的选择: ");
  18.                 scanf("%d", &isWorking);
  19.                 switch(isWorking)
  20.                 {
  21.                 case 0:
  22.                         break;
  23.                 case 1:
  24.                         if (pid == 0)
  25.                         {
  26.                                 printf("子进程不存在\n");
  27.                                 break;
  28.                         }
  29.                         kill(pid, 16);
  30.                         break;
  31.                 case 2:
  32.                         if (pid == 0)
  33.                         {
  34.                                 printf("子进程不存在\n");
  35.                                 break;
  36.                         }
  37.                         kill(pid, 17);
  38.                         pid = 0;
  39.                         break;
  40.                 default:
  41.                         isWorking = 0;
  42.                 }
  43.         }
  44. }

  45. void sub_fork_working()
  46. {
  47.         printf("别烦我,正忙着呢!\n");
  48. }

  49. void sub_fork_quit()
  50. {
  51.         printf("子进程退出\n");
  52.         isWorking = 0;
  53. }

  54. void sub_fork()
  55. {
  56.         signal(16, sub_fork_working);
  57.         signal(17, sub_fork_quit);

  58.         while(isWorking)
  59.         {
  60.                 sleep(1);
  61.         }
  62. }

  63. int main()
  64. {
  65.         pid_t pid;

  66.         pid = fork();

  67.         if (pid > 0)
  68.                 parent_fork(pid);
  69.         else
  70.                 sub_fork();

  71.         return 0;
  72. }
复制代码

执行结果:

  1. root@yxm:~/c++/test# cc forksignal2.c -o forksignal2
  2. root@yxm:~/c++/test# ./forksignal2
  3. 0. 退出
  4. 1. 向子进程发信号
  5. 2. 退出子进程
  6. 请输入您的选择: 1
  7. 0. 退出
  8. 1. 向子进程发信号
  9. 2. 退出子进程
  10. 请输入您的选择: 别烦我,正忙着呢!
  11. 1
  12. 0. 退出
  13. 1. 向子进程发信号
  14. 2. 退出子进程
  15. 请输入您的选择: 别烦我,正忙着呢!
  16. 1
  17. 别烦我,正忙着呢!
  18. 0. 退出
  19. 1. 向子进程发信号
  20. 2. 退出子进程
  21. 请输入您的选择: 2
  22. 子进程退出
  23. 0. 退出
  24. 1. 向子进程发信号
  25. 2. 退出子进程
  26. 请输入您的选择: 2
  27. 子进程不存在
  28. 0. 退出
  29. 1. 向子进程发信号
  30. 2. 退出子进程
  31. 请输入您的选择: 0
  32. root@yxm:~/c++/test#
复制代码

终于达到设计本意。
附:signal与kill的manpage

  1. root@yxm:~# man signal
  2. Reformatting signal(2), please wait...
  3. SIGNAL(2)                Linux Programmer's Manual                SIGNAL(2)

  4. NAME
  5.        signal - ANSI C signal handling

  6. SYNOPSIS
  7.        #include <signal.h>

  8.        typedef void (*sighandler_t)(int);

  9.        sighandler_t signal(int signum, sighandler_t handler);

  10. DESCRIPTION
  11.        The  signal() system call installs a new signal handler for the sig-
  12.        nal with number signum.  The signal handler  is  set  to  sighandler
  13.        which  may  be  a  user  specified  function,  or  either SIG_IGN or
  14.        SIG_DFL.

  15.        Upon arrival of a signal with number signum the  following  happens.
  16.        If  the  corresponding handler is set to SIG_IGN, then the signal is
  17.        ignored.  If the handler is set to SIG_DFL, then the default  action
  18.        associated  with the signal (see signal(7)) occurs.  Finally, if the
  19.        handler is set to a function sighandler then first either  the  han-
  20.        dler  is reset to SIG_DFL or an implementation-dependent blocking of
  21.        the signal is performed and next sighandler is called with  argument
  22.        signum.

  23.        Using a signal handler function for a signal is called "catching the
  24.        signal".  The signals  SIGKILL  and  SIGSTOP  cannot  be  caught  or
  25.        ignored.

  26. RETURN VALUE
  27.        The  signal() function returns the previous value of the signal han-
  28.        dler, or SIG_ERR on error.

  29. PORTABILITY
  30.        The original Unix signal() would reset the handler to  SIG_DFL,  and
  31.        System  V  (and the Linux kernel and libc4,5) does the same.  On the
  32.        other hand, BSD does not reset the handler, but blocks new instances
  33.        of  this  signal  from  occurring during a call of the handler.  The
  34.        glibc2 library follows the BSD behaviour.

  35.        If one on a libc5 system includes <bsd/signal.h>  instead  of  <sig-
  36.        nal.h> then signal() is redefined as __bsd_signal and signal has the
  37.        BSD semantics. This is not recommended.

  38.        If one on a glibc2 system defines  a  feature  test  macro  such  as
  39.        _XOPEN_SOURCE  or  uses a separate sysv_signal function, one obtains
  40.        classical behaviour. This is not recommended.

  41.        Trying to change the  semantics  of  this  call  using  defines  and
  42.        includes  is  not  a good idea. It is better to avoid signal() alto-
  43.        gether, and use sigaction(2) instead.

  44. NOTES
  45.        The effects of this call in a multi-threaded  process  are  unspeci-
  46.        fied.

  47.        The routine handler must be very careful, since processing elsewhere
  48.        was interrupted at some arbitrary point. POSIX has  the  concept  of
  49.        "safe  function".   If  a  signal interrupts an unsafe function, and
  50.        handler calls an unsafe function, then the  behavior  is  undefined.
  51.        Safe  functions are listed explicitly in the various standards.  The
  52.        POSIX 1003.1-2003 list is

  53.        _Exit() _exit() abort() accept() access()  aio_error()  aio_return()
  54.        aio_suspend()    alarm()    bind()    cfgetispeed()    cfgetospeed()
  55.        cfsetispeed() cfsetospeed() chdir() chmod() chown()  clock_gettime()
  56.        close()  connect()  creat()  dup() dup2() execle() execve() fchmod()
  57.        fchown() fcntl()  fdatasync()  fork()  fpathconf()  fstat()  fsync()
  58.        ftruncate()  getegid()  geteuid() getgid() getgroups() getpeername()
  59.        getpgrp() getpid()  getppid()  getsockname()  getsockopt()  getuid()
  60.        kill() link() listen() lseek() lstat() mkdir() mkfifo() open() path-
  61.        conf() pause() pipe() poll() posix_trace_event()  pselect()  raise()
  62.        read()  readlink()  recv()  recvfrom()  recvmsg()  rename()  rmdir()
  63.        select() sem_post() send()  sendmsg()  sendto()  setgid()  setpgid()
  64.        setsid()  setsockopt()  setuid()  shutdown() sigaction() sigaddset()
  65.        sigdelset() sigemptyset() sigfillset() sigismember()  signal()  sig-
  66.        pause()  sigpending() sigprocmask() sigqueue() sigset() sigsuspend()
  67.        sleep() socket() socketpair() stat() symlink()  sysconf()  tcdrain()
  68.        tcflow() tcflush() tcgetattr() tcgetpgrp() tcsendbreak() tcsetattr()
  69.        tcsetpgrp()  time()  timer_getoverrun()  timer_gettime()  timer_set-
  70.        time()  times()  umask()  uname()  unlink() utime() wait() waitpid()
  71.        write().

  72.        According to POSIX, the behaviour of a process is undefined after it
  73.        ignores  a  SIGFPE, SIGILL, or SIGSEGV signal that was not generated
  74.        by the kill(2) or the raise(3) functions.  Integer division by  zero
  75.        has  undefined  result.   On  some  architectures it will generate a
  76.        SIGFPE signal.  (Also dividing the most negative integer by  -1  may
  77.        generate  SIGFPE.)   Ignoring  this  signal might lead to an endless
  78.        loop.

  79.        See sigaction(2) for details on what happens when SIGCHLD is set  to
  80.        SIG_IGN.

  81.        The  use  of  sighandler_t  is a GNU extension.  Various versions of
  82.        libc predefine this type;  libc4  and  libc5  define  SignalHandler,
  83.        glibc  defines  sig_t and, when _GNU_SOURCE is defined, also sighan-
  84.        dler_t.

  85. CONFORMING TO
  86.        ANSI C

  87. SEE ALSO
  88.        kill(1), alarm(2), kill(2), pause(2),  sigaction(2),  sigpending(2),
  89.        sigprocmask(2),  sigqueue(2),  sigsuspend(2),  killpg(3),  raise(3),
  90.        sigsetops(3), sigvec(3), feature_test_macros(7), signal(7)

  91. Linux 2.2                        2000-04-28                       SIGNAL(2)
  92. Manual page signal(2) line 75/114 (END)
复制代码

  1. root@yxm:~# man 2 kill
  2. Reformatting kill(2), please wait...
  3. KILL(2)                  Linux Programmer's Manual                  KILL(2)

  4. NAME
  5.        kill - send signal to a process

  6. SYNOPSIS
  7.        #include <sys/types.h>
  8.        #include <signal.h>

  9.        int kill(pid_t pid, int sig);

  10. DESCRIPTION
  11.        The kill() system call can be used to send any signal to any process
  12.        group or process.

  13.        If pid is positive, then signal sig is sent to pid.

  14.        If pid equals 0, then sig is sent to every process  in  the  process
  15.        group of the current process.

  16.        If  pid  equals  -1, then sig is sent to every process for which the
  17.        calling process has permission to send signals, except for process 1
  18.        (init), but see below.

  19.        If  pid  is  less  than -1, then sig is sent to every process in the
  20.        process group -pid.

  21.        If sig is 0, then no signal is sent, but  error  checking  is  still
  22.        performed.

  23.        For  a process to have permission to send a signal it must either be
  24.        privileged (under Linux: have the CAP_KILL capability), or the  real
  25.        or  effective  user ID of the sending process must equal the real or
  26.        saved set-user-ID of the target process.  In the case of SIGCONT  it
  27.        suffices when the sending and receiving processes belong to the same
  28.        session.

  29. RETURN VALUE
  30.        On success (at least one signal was sent),  zero  is  returned.   On
  31.        error, -1 is returned, and errno is set appropriately.

  32. ERRORS
  33.        EINVAL An invalid signal was specified.

  34.        EPERM  The  process  does  not have permission to send the signal to
  35.               any of the target processes.

  36.        ESRCH  The pid or process group does not exist.  Note that an exist-
  37.               ing  process  might be a zombie, a process which already com-
  38.               mitted termination, but has not yet been wait()ed for.

  39. NOTES
  40.        The only signals that can be sent task number one, the init process,
  41.        are  those  for which init has explicitly installed signal handlers.
  42.        This is done to assure the system is not brought down  accidentally.

  43.        POSIX  1003.1-2001  requires  that kill(-1,sig) send sig to all pro-
  44.        cesses that the current process may send signals to, except possibly
  45.        for  some  implementation-defined  system processes.  Linux allows a
  46.        process to signal itself, but on Linux the  call  kill(-1,sig)  does
  47.        not signal the current process.

  48.        POSIX  1003.1-2003  requires  that  if  a  process sends a signal to
  49.        itself, and the sending thread does not have the signal blocked, and
  50.        no  other thread has it unblocked or is waiting for it in sigwait(),
  51.        at least one unblocked signal  must  be  delivered  to  the  sending
  52.        thread before the kill().

  53. BUGS
  54.        In 2.6 kernels up to and including 2.6.7, there was a bug that meant
  55.        that when sending signals to a process group, kill() failed with the
  56.        error  EPERM if the caller did have permission to send the signal to
  57.        any (rather than all) of the embers of the process group.   Notwith-
  58.        standing this error return, the signal was still delivered to all of
  59.        the processes for which the caller had permission to signal.

  60. LINUX HISTORY
  61.        Across different kernel versions, Linux has enforced different rules
  62.        for  the  permissions required for an unprivileged process to send a
  63.        signal to another process.  In kernels 1.0 to 1.2.2, a signal  could
  64.        be  sent  if the effective user ID of the sender matched that of the
  65.        receiver, or the real user ID of the  sender  matched  that  of  the
  66.        receiver.  From kernel 1.2.3 until 1.3.77, a signal could be sent if
  67.        the effective user ID of the  sender  matched  either  the  real  or
  68.        effective user ID of the receiver.  The current rules, which conform
  69.        to POSIX 1003.1-2001, were adopted in kernel 1.3.78.

  70. CONFORMING TO
  71.        SVr4, SVID, POSIX.1, X/OPEN, 4.3BSD, POSIX 1003.1-2001

  72. SEE ALSO
  73.        _exit(2),  killpg(2),  signal(2),  sigqueue(2),  tkill(2),  exit(3),
  74.        capabilities(7), signal(7)

  75. Linux 2.6.7                      2004-06-24                         KILL(2)
  76. Manual page kill(2) line 60/99 (END)
复制代码
回复 支持 反对

使用道具 举报

发表于 2007-8-22 09:30:18 | 显示全部楼层
Post by cccer
我这里测试大部分时候都是子进程先运行,但是这也是没有保证的。


《Unix网络编程实用技术与实例分析》P70上是这么说的:

“一般情况下,在调用fork()函数之后是父进程先执行,还是子进程先执行是不确定的。这取决于内核做使用的调度算法。”
回复 支持 反对

使用道具 举报

发表于 2007-8-22 12:44:55 | 显示全部楼层
在fork()调用中, 内核总是有意选择子进程首先执行.
但是实际中有时候并不一定这样.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表