Unix中的进程

来源:互联网 发布:ed2k linux用什么下载 编辑:程序博客网 时间:2024/06/05 18:15

1:进程ID

每个进程都有一个非负整数表示的唯一进程ID。虽然是唯一的,但是进程ID可以重用。大多数Unix系统实现延迟重用算法。进程ID用pid_t表示。

一下两个函数用来得到当前进程和父进程的pid。

#include<unistd.h>pid_t getpid();//get pid of current processspid_t getppid();//get pid of parent process

2:创建新进程

#include<unistd.h>pid_t fork();
fork函数被调用一次,但返回两次。子进程返回0,父进程返回子进程的进程ID。将子进程ID返回给父进程的理由是:因为一个进程的子进程可以有多个,并且没有一个函数可以得到一个进程的所有子进程的进程ID。fork使子进程得到返回值0的理由是:一个进程只有一个父进程,并且子进程可以通过getppid得到父进程的进程ID。
#include<unistd.h>#include<string.h>#include<stdio.h>#include<sys/wait.h>int glob=6;char buf[]="a write to stdout\n";void printErr(const char* info){    write(STDERR_FILENO,info,strlen(info));    _exit(1);}int main(){    int var=10;    pid_t pid;    if(write(STDOUT_FILENO,buf,strlen(buf))!=strlen(buf))        printErr("Write Error\n");    printf("pid=%d,before fork1\n",getpid());    if((pid=fork())<0)//括号不能少        printErr("fork error\n");    else if(pid==0){        glob++;        var++;    }else{        sleep(5);        wait(NULL);//在wait返回前子进程是僵尸进程,返回后就不是僵尸进程了        printf("father after waitpid\n");        sleep(5);    }    printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var);    return 0;}
编译后可执行文件为test1,在终端执行 ./test1,输出如下:a write to stdoutpid=5272,before fork1pid=5273,glob=7,var=11father after waitpidpid=5272,glob=6,var=10讲输出重定向到文件,./test1 >tmp.txt,然后显示文件cat tmp.txt,输出如下:a write to stdoutpid=5274,before fork1pid=5275,glob=7,var=11pid=5274,before fork1father after waitpidpid=5274,glob=6,var=10

可见重定向到文件后多数出了下面一行,是因为缓冲的缘故:write函数没有缓冲,因此只输出一行。标准I/O(printf)是有缓冲的,如果输出到终端设备是行缓冲的(由于有\n因此缓冲区被冲洗),在终端只输出一次。标准I/O输出到文件是全缓冲的,因此在在子进程的最后一行输出后会把缓冲区内的内容输出

pid=5274,before fork1
3:僵尸进程

当父进程fork之后创建了子进程后,如果子进程先结束,并且父进程没有wait或waitpid等待子进程,那么子进程变为僵尸进程,知道父进程结束才不是僵尸进程。

如果父进程先结束,那么子进程的父进程变为init进程。init进程的子进程结束后,init进程会调用一个wait函数取得其终止状态。

上面的程序子进程很快执行完毕,在父进程执行wait之前子进程变为僵尸进程,wait执行之后就不是僵尸进程了。可以使用下面的命令来查看当前的僵尸进程。

ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'
#include<sys/wait.h>pid_t wait(int * statloc);pid_t waitpid(pid_t pid,int* statloc,int options);两个函数返回值:若成功则返回进程ID,出错返回-1

僵尸进程的危害:僵尸进程是一个运行完毕的进程,所有的资源都已经释放了,包括打开的文件,占用的内存等等。但是仍然为其保留一定的信息(包括进程号,退出状态,运行时间等),直到父进程通过wait/waitpid来取时才释放。否则的话这些信息会一直保存,进程号就会被一直占用,但是系统所能使用的进程号是有限的,如果产生大量的僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程。

解决僵尸进程的方法:如果一个进程fork一个子进程,但不要它等待子进程终止,也不希望子进程处于僵死状态知道父进程终止,实现这一要求的技巧是调用fork两次。
代码如下:

#include<unistd.h>#include<stdio.h>#include<string.h>#include<sys/wait.h>#include<stdlib.h>void printErr(const char* info){    write(STDERR_FILENO,info,strlen(info));    _exit(1);}int main(){    pid_t pid;    if((pid=fork())<0)        printErr("fork1 error\n");    else if(pid==0){        if((pid=fork())<0)            printErr("fork2 error\n");        else if(pid>0){            printf("first child,pid=%d,ppid=%d\n",getpid(),getppid());            _exit(0);        }        sleep(1);        printf("second child,pid=%d,ppid=%d\n",getpid(),getppid());        _exit(0);    }    if(waitpid(pid,NULL,0)!=pid)        printErr("waitpid error\n");    printf("parent pid=%d\n",getpid());    return 0;}




0 0