进制控制原语

来源:互联网 发布:2017年淘宝好做吗 编辑:程序博客网 时间:2024/05/20 05:03

fork函数

由fork创建的新进程被称为子进程(child process),fork函数被调用一次,但返回两次。两次返回的唯一区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID。将子进程ID返回给父进程的理由是:因为一个进程的子进程可以有多个,并且没有一个函数使一个进程可以获得其所有子进程的进程ID。fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用getppid以获得其父进程的进程ID(进程ID 0 总是由内核交换进程使用,所以一个子进程的进程ID不可能为 0)。子进程是父进程的副本。
//fork - create a child process,返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1#include <unistd.h>pid_t fork(void);

父、子进程之间的区别是:

  1. 列表内容
  2. fork的返回值
  3. 进程ID不同
  4. 两个进程具有不同的父进程ID:子进程的父进程ID是创建它的进程的ID,而父进程的父进程ID则不变
  5. 子进程的tms_utime,tms_stime,tms_cutime以及tms_ustime均被设置为0
  6. 父进程设置的文件锁不会被子进程
  7. 子进程的未处理的闹钟( alarm )被清除
  8. 子进程的未处理信号集设置为空集

fork有两种用法:

  1. 一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的–父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。
  2. 一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec

使用fork失败的主要原因是:

  1. 系统中已经有了太多的进程
  2. 该实际用户ID的进程总数超过了系统限制
/*****************************************> File Name : fork.cpp> Description : fork两次,避免僵死进程    gcc -g -o fork fork.cpp> Author : linden> Date : 2016-01-25*******************************************/#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <sys/wait.h>#include <sys/types.h>int main(void){    pid_t pid;    if ((pid = fork()) < 0)    {        fprintf(stderr, "Fork error!\n");        exit(-1);    }    else if (pid == 0) /* first child */    {        if ((pid = fork()) < 0)        {            fprintf(stderr, "Fork error!\n");            exit(-1);        }        else if (pid > 0)            exit(0); /* parent from second fork == first child */        /*        * We're the second child; our parent becomes init as soon        * as our real parent calls exit() in the statement above.        * Here's where we'd continue executing, knowing that when        * we're done, init will reap our status.        */        sleep(2);        printf("Second child, parent pid = %d\n", getppid());        exit(0);    }    if (waitpid(pid, NULL, 0) != pid) /* wait for first child */    {        fprintf(stderr, "Waitpid error!\n");        exit(-1);    }    /*    * We're the parent (the original process); we continue executing,    * knowing that we're not the parent of the second child.    */    exit(0);}

wait和waitpid函数

调用wait或waitpid的进程可能会发生的情况:

  • 如果其所有子进程都还在运行,则阻塞
  • 如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回
  • 如果它没有任何子进程,则立即出错返回

如果进程由于接收到SIGCHLD信号而调用wait,则可期望wait会立即返回。但是如果在任意时刻调用wait,则进程可能会阻塞。

//参数statloc是一个整型指针。如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内。如果不关心终止状态,则可将该参数指定为空指针。两者返回值:若成功返回进程ID,0,若出错返回-1#include <sys/wait.h>pid_t wait(int *statloc);pid_t waitpid(pid_t pid, int *statloc, int options);

两函数区别:

  • 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞
  • waitpid并不等待在其调用之后的第一个终止子进程,它有若干个选项,可以控制它所等待的进程
/*****************************************> File Name : fork.cpp> Description : fork示例代码    gcc -g -o fork fork.cpp> Author : linden> Date : 2016-01-22*******************************************/#include <unistd.h>#include <stdio.h>#include <errno.h>#include <stdlib.h>#include <sys/types.h>#include <sys/wait.h>void pre_exit(int status){    if (WIFEXITED(status))    {        printf("normal termination,exit status = %d\n", WEXITSTATUS(status));    }    else if (WIFSIGNALED(status))    {        printf("abnormal termination,signal number = %d%s\n", WTERMSIG(status),#ifdef WCOREDUMP            WCOREDUMP(status) ? " (core fire generated) " : "");#else            "");#endif    }    else if (WIFSTOPPED(status))    {        printf("child stopped,signal number = %d\n",WSTOPSIG(status));    }}int main(int argc, char *argv[]){    pid_t pid;    pid = fork();    if (0 > pid)    {        perror("fork error:");    }    else if (0 == pid)    {        printf("This is the child process: %d, ppid = %d.\n", getpid(),getppid());        exit(0);    }    printf("This is the parent process: %d.\n", getpid());    //判断子进程结束:wait子进程结束    int status;    if (wait(&status) != pid)     {        perror("Error --> wait:");    }    pre_exit(status);    return 0;}
0 0
原创粉丝点击