Unix高级环境编程—进程控制(一)

一、函数fork

#include<unistd.h>

pid_t  fork(void)                                                                    子进程返回0,父进程返回子进程ID,出错返回-1

 

    fork函数被调用一次,返回两次。先返回父进程还是子进程是不确定的,取决于内核使用的调度算法。

    子进程和父进程并不共享存储空间,而是共享正文段。因此,子进程对变量所做的改变并不影响父进程中该变量的值。

    父进程和子进程共享同一个文件偏移量。fork之后处理fd的两种情况:

(1)父进程等待子进程完成,当子进程完成操作后,它们任一共享的fd的文件偏移量,已经更新,父进程可以接着子进程继续工作。

(2)父进程和子进程各自执行不同的程序段,fork之后,父进程和子进程各自关闭它们不需要使用的fd,这样就不会干扰对方使用的fd,否则产生的文件偏移量会共享给对方,由于是执行不同的程序段,所以会产生干扰。(常用于网络服务进程,Socket通信中的server

父进程与子进程的区别如下:

v    fork的返回值不同

v    进程ID不同

v    两个进程的父进程ID不同

v    子进程的tms_utimetms_stimetms_cutimetms_ustime、的值设置为0.

v    子进程不继承父进程设置的文件锁。

v    子进程的未处理闹钟被清除。

v    子进程的未处理信号集设置为空集。

  标准fork用法示例:已备后续查看


#include "apue.h"

int             globvar = 6;            /* external variable in initialized data */
char    buf[] = "a write to stdout\n";

int
main(void)
{
        int             var;            /* automatic variable on the stack */
        pid_t   pid;

        var = 88;
        if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
                err_sys("write error");
        printf("before fork\n");        /* we don't flush stdout */

        if ((pid = fork()) < 0) {
                err_sys("fork error");
        } else if (pid == 0) {          /* child */
                globvar++;                              /* modify variables */
                var++;
        } else {
                sleep(2);                               /* parent */
        }

        printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar,
          var);
        exit(0);
}

 

 

二、函数vfork

fork的区别:

(1).vfork也是创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为vfork的目的是让子进程立即exec一个启动例程,这样,它也就不会引用该地址空间。

(2).vfork保证子进程先运行,在它调用execexit之后父进程才可能被调度运行,否则,会导致死锁。而fork之后父进程和子进程谁先执行是不确定的。

 

 

三、函数exit

进程的8种终止状态:

正常终止为:

(1).main返回

(2).调用exit

(3)调用_exit_Exit

(4)最后一个线程从其启动例程返回

(5)从最后一个线程调用pthread_exit

异常终止为:

(6)调用abort

(7)接到一个信号终止

(8)最后一个线程对取消请求做出响应

   在任意一种情况下,该终止进程的父进程都能用waitwaitpid函数取得其终止状态。

有意思的两种情况:

(1).父亲先死:

   如果父进程在子进程之前终止,那么这些子进程的父进程变为init进程,称这些子进程由init进程收养。(这里很有意思,就是说如果父亲在儿子之前死了,那么这些孩子都会被init这个孤儿收容所所认,都成了init的儿子。) 

 父进程30314 fork了子进程30315

  


kill -9 30314 我们杀死父亲之后,

  


果然,子进程被init进程收养,并在sleeping状态。

 

(2).儿子先死

  如果子进程完全消失了,父进程在最终准备好检查子进程是否终止时是无法获取它的状态的,内核为每个终止子进程保存了一定量的信息,所以父进程调用waitwaitpid可以得到这些信息。在Unix中,如果父进程无法获取子进程的终止状态,那么这些子进程会变为僵死进程。(形象的说,如果父亲不负责任,他对自己儿子的死一无所知,那么这个孩子死不瞑目,变为僵死状态。)

  

 

这回我们还是先fork一个子进程,kill -9 30425 ,先杀死儿子,我们看到父进程还在后台运行,由于我们用kill -9属于“偷偷”杀死的儿子,父亲无法获取儿子的死讯,因此,儿子变为僵死进程。

 

此外,init被编写成无论何时只要有一个子进程终止,init就会调用一个wait函数取得其终止状态。防止在系统中塞满僵死进程。


转载于:https://www.cnblogs.com/webber1992/p/5850759.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值