Unix中的进程

1:进程ID

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

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

#include<unistd.h>

pid_t getpid();//get pid of current processs

pid_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 stdout
pid=5272,before fork1
pid=5273,glob=7,var=11
father after waitpid
pid=5272,glob=6,var=10
讲输出重定向到文件,./test1 >tmp.txt,然后显示文件cat tmp.txt,输出如下:
a write to stdout
pid=5274,before fork1
pid=5275,glob=7,var=11
pid=5274,before fork1
father after waitpid
pid=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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值