进程基本介绍

来源:互联网 发布:淘宝开店得多少钱2016 编辑:程序博客网 时间:2024/06/07 15:13

1、进程创建

   pid_t fork();

  fork 返回的值非常有趣。其中一个返回 0;另一个返回一个非零值。获得 0 的进程称为子进程,非零结果属于原始进程,即父进程.

int main(){    pid_t pid;    pid = fork();        printf("mypid = %d, my paraent pid = %d, call pid = %d \n", getpid(), getppid(), pid);    exit(0);}

执行结果

mypid = 888982, my paraent pid = 1409130, call pid = 553050 

mypid = 553050, my paraent pid = 888982, call pid = 0 

看到fork创建一个新的进程553050,返回值pid为0,父进程888982,返回值为子进程ID,fork调用一次,返回两次。

2、僵死进程

       当子进程比父进程提前退出,但是没有告诉父进程退出情况,导致子进程不会被内核回收,而一直存在进程表空间。需要等父进程退出后内核最终能够回收未确认的子进程以及父进程,这意味着可消除僵死进程的唯一方法是终止父进程。但是如何防止出现僵死进程呢?先看代码,后面再说

int main(){    pid_t pid;    pid = fork();    if (pid == 0)    {        printf("mypid = %d, my paraent pid = %d, call pid = %d \n", getpid(), getppid(), pid);        exit(0);    }    sleep(60);    printf("mypid = %d, my paraent pid = %d, call pid = %d \n", getpid(), getppid(), pid);    exit(0);}

 1515654                            Z                  0:00 <defunct>

1392728  0.0  0.0  148  380 pts/36 A    10时39分59秒  0:00 ./fort_t

查看进程表,发现子进程实效(defunct),但是进程ID还存在,这就是僵死进程了。

如何避免僵死进程呢?

        使用信号机制,当子进程终止时,会使用一个名为 SIGCHLD 的信号来通知其父进程。看代码

#include <unistd.h>#include <sys/wait.h>#include <sys/types.h>void sighander(int sig){    printf("hander sig is %d\n", sig);    wait(0);}   int main(){    pid_t pid;    pid = fork();        sigset(SIGCHLD, &sighander);    if (pid == 0)    {        printf("mypid = %d, my paraent pid = %d, call pid = %d \n", getpid(), getppid(), pid);        exit(0);    }           sleep(60);    printf("mypid = %d, my paraent pid = %d, call pid = %d \n", getpid(), getppid(), pid);    exit(0);}   

        由于使用了 sigset 函数(它向信号处理程序分配一个函数指针)。每当进程接收到某个已处理的信号时,就会调用通过 sigset 分配的函数。对于 SIGCHLD 信号,应用程序必须调用wait() 函数,以等待子进程退出。由于该进程已经退出,这相当于向内核确认了子进程的终止。实际上,父进程所做的工作可能不只是确认该信息。它还可能需要清理子进程的数据。

3、wait

         pid_t wait(int *statloc);     //函数若成功,返回进程ID,若出错则返回-1; 

        如果一个进程结束了,不论是正常的还是非正常的,内核都会通过发送SIGCHLD 信号给父进程。子进程的结束是个异步事件,父进程执行这个信号,通过内核的异步通知,父进程可以选择忽略该信号,或者提供一个该信号发生时即被调用执行的函数。对于这种信号的系统默认动作是忽略它。

父进程通过调用wait 和waitpid,有如下调用情况

① :如果所有的子进程正在运行,父进程阻塞。

②:如果一个子进程结束了,父进程通过wait 取得了结束进程的状态值,父进程会立即随着子进程的结束状态返回。 

③:如果进程没有子进程那么返回error 。

#include <unistd.h>#include <sys/wait.h>#include <sys/types.h>#include <sys/errno.h>#include <vector.h>#define MAX_SIZE 5void sighander(int sig){    printf("hander sig is %d\n", sig);    wait(0);}int main(){    pid_t pid;    vector<pid_t> vSubPid;    //sigset(SIGCHLD, &sighander);    for (int i = 0; i < MAX_SIZE; ++i)    {        pid = fork();        if (pid == 0)        {            printf("mypid = %d, my paraent pid = %d, call pid = %d \n", getpid(), getppid(), pid);            exit(i);        }        else        {            vSubPid.push_back(pid);        }    }    int status = 0;    int num = 0;    pid_t wait_pid;    while (num < vSubPid.size())    {        wait_pid = wait(&status);        if (wait_pid == -1)        {            printf("wait error, no(%d), %s\n", errno, strerror(errno));            return -1;        }        if (WIFEXITED(status))        {            if(WEXITSTATUS(status) < 0) {                printf("SubProcess(%d) return err value=%#x\n", wait_pid, WEXITSTATUS(status));                return -1;            }else {                printf("SubProcess(%d) return value=%#x \n", wait_pid, WEXITSTATUS(status));            }        }        num++;    }    printf("mypid = %d, my paraent pid = %d, call pid = %d \n", getpid(), getppid(), pid);    exit(0);}

执行结果




这个例子主要是用了宏WIFEXITED()和WEXITSTATUS来对子进程的状态进行控制

WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。

WEXITSTATUS(status) 当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)退出,WEXITSTATUS(status) 就会返回5;如果子进程调用exit(7),WEXITSTATUS(status)就会返回7。请注意,如果进程不是正常退出的,也就是说, WIFEXITED返回0,这个值就毫无意义。

4、Waitpid函数

    pit_t wait(pid_t pid,int *status,int options);  

  当我们需要等待一个特定进程的函数时候,我们这个时候需要用到了waitpid函数了。从上文看到waitpid函数原型,我们也都了解到有个pid_t参数。

解释如下:

Pid=-1,等待任一个子进程,与wait等效。

Pid>0.等待其进程ID与pid相等的子进程。

Pid==0等待其组ID等于调用进程组ID的任一个子进程。

Pid<-1等待其组ID等于pid绝对值的任一子进程

这个就不举例子了,大家可以自己试试。



0 0
原创粉丝点击