linux-进程的初步认识

1. 什么是进程?

  1. 进程是一个运行着的程序,它包含了程序在运行时的各个资源,进程是linux进行调度的基本单位,也是一个程序运行的基本单位。
  2. 进程就好比多任务,在我们编程中,进程就好比多个main在同时执行.

2. 进程状态

进程是程序的执行过程,根据它的生命周期可以划分成 3 种状态。

执行态:
	该进程正在运行,即进程正在占用 CPU, 任何时候都只有一个进程。
就绪态:
	进程已经具备执行的一切条件,正在等待分配 CPU 的处理时间片。
等待态:
	进程正在等待某些事件,当前不能分配时间片,进程不能使用 CPU,
	若等待事件发生(等待的资源分配到)则可将其唤醒,变成就绪态。

3. 父子进程

3.1 PID和PPID

函数功能:
    获取自己的进程PID
    获取父进程的PPID
函数头文件:
    #include <sys/types.h>
    #include <unistd.h>
函数原型:
    pid_t getpid(void);
    pid_t getppid(void);
函数参数:
    无
函数返回值:
    返回的就是你需要的PID号

代码:

void Test_Pid(void)
{
    pid_t pd,ppd;
    pd = getpid();
    ppd = getppid();
    printf("自己的进程号==%d\n",pd);
    printf("父亲的进程号==%d\n",ppd);
}

结果:
在这里插入图片描述

3.2 fork

函数功能:在一个进程中创建一个子进程
函数头文件:<unistd.h>
函数原型:
        pid_t fork(void)
函数参数:
        无
函数返回值:
        在本进程(父进程)
                返回子进程的ID
        在子进程
                返回 0
        返回负值
        		表示创建子进程失败
特点:
    该函数会完全复制父进程的所有资源
	但是会从fork之下开始运行
	子进程所独有的只有它的进程号

代码:

//测试创建子进程函数fork()  
void Test_fork(void)
{
    int a=10;
    char * str = "hello";
    pid_t pd;
    pid_t pd1,pd2;
    printf("测试........\n");
    pd = fork();//从这句话开始创建子进程
    if(pd>0)//父进程
    {
        sleep(2);
        pd1 = getpid();
        pd2 = getppid();
        printf("i am father\n");
        printf("father 返回进程号==%d\n",pd);
        printf("father 自己的进程号==%d\n",pd1);
        printf("father 父亲的进程号==%d\n",pd2);
        printf("a == %d\n",a);
    }else //子进程
    {
        pd1 = getpid();
        pd2 = getppid();
        printf("i am son\n");
        printf("son 返回进程号==%d\n",pd);
        printf("son 自己的进程号==%d\n",pd1);
        printf("son 父亲的进程号==%d\n",pd2);
        a++;
    }
}

结果:
在这里插入图片描述

3.3 vfork

函数功能:在一个进程中创建一个子进程
函数头文件:<unistd.h>
函数原型:
        pid_t vfork(void)
函数参数:
        无
函数返回值:
        在本进程(父进程)
                返回子进程的ID
        在子进程
                返回 0    
vfork:
    这个函数跟fork功能基本一致
    只不过fork真正的创建了两个进程
    而vfork虽然也是创建了两个进程
    但是本质上来讲它只创建了一个

    *会阻塞父进程
    *必须等到子进程运行完毕(死掉)
    *他才开始运行
    *子进程跟父进程共占一个资源
    *子进程结束exit函数之后 
     才会去运行父进程否则会发生段错误
     fork:子进程拷贝父进程的数据段、堆栈段
     vfork:父子进程共享数据段

代码:

//测试创建子进程函数vfork()  
void Test_vfork(void)
{
    int a=10;
    char * str = "hello";
    pid_t pd;
    pid_t pd1,pd2;
    printf("测试........\n");
    pd = vfork();//从这句话开始创建子进程
    if(pd>0)//父进程
    {
        pd1 = getpid();
        pd2 = getppid();
        printf(" i am father\n");
        printf("father 返回进程号==%d\n",pd);
        printf("father 自己的进程号==%d\n",pd1);
        printf("father 父亲的进程号==%d\n",pd2);
        printf("a == %d\n",a);
    }else //子进程
    {
        pd1 = getpid();
        pd2 = getppid();
        printf(" i am son\n");
        printf("son 返回进程号==%d\n",pd);
        printf("son 自己的进程号==%d\n",pd1);
        printf("son 父亲的进程号==%d\n",pd2);
        a++;
        exit(0);
    }
}

结果:
在这里插入图片描述
如果exit(0)屏蔽掉:
在这里插入图片描述

4. 孤儿进程

一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

子进程死亡需要父进程来处理,那么意味着正常的进程应该是子进程先于父进程死亡。当父进程先于子进程死亡时,子进程死亡时没父进程处理,这个死亡的子进程就是孤儿进程。

代码:

//测试孤儿进程
void Test_Guer(void)
{
    int a=10;
    char * str = "hello";
    pid_t pd;
    pid_t pd1,pd2;
    printf("测试........\n");
    pd = fork();//从这句话开始创建子进程
    if(pd>0)//父进程
    {
        pd1 = getpid();
        pd2 = getppid();
        printf("i am father\n");
        printf("father 返回进程号==%d\n",pd);
        printf("father 自己的进程号==%d\n",pd1);
        printf("father 父亲的进程号==%d\n",pd2);
        printf("a == %d\n",a);
        exit(0);
    }else //子进程
    {
        sleep(2);
        pd1 = getpid();
        pd2 = getppid();
        printf("i am son\n");
        printf("son 返回进程号==%d\n",pd);
        printf("son 自己的进程号==%d\n",pd1);
        printf("son 父亲的进程号==%d\n",pd2);
        a++;
    }
}

结果:
在这里插入图片描述

5. 僵尸进程

子进程退出,父进程没有做清理工作。一种非常特殊的进程,它几乎已经 放弃了所有内存空间,没有任何可执行代码, 也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供 其他进程收集,除此之外,僵尸进程不再占有任何内存空间,父进程退出会清理子进程 。

这个僵尸进程需要它的父进程来为它收尸,如果他的父进程没有处理这个僵尸进程的措施,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。

试想一下,如果有大量的僵尸进程驻在系统之中,必然消耗大量的系统资源。但是系统资源是有限的,因此当僵尸进程达到一定数目时,系统因缺乏资源而导致奔溃。所以在实际编程中,避免和防范僵尸进程的产生显得尤为重要。

代码:

//测试僵尸进程
void Test_Z_jincheng(void)
{
    int a=10;
    char * str = "hello";
    pid_t pd;
    pid_t pd1,pd2;
    printf("测试........\n");
    pd = fork();//从这句话开始创建子进程
    if(pd>0)//父进程
    {
        pd1 = getpid();
        pd2 = getppid();
        printf(" i am father\n");
        printf("father 返回进程号==%d\n",pd);
        printf("father 自己的进程号==%d\n",pd1);
        printf("father 父亲的进程号==%d\n",pd2);
        printf("a == %d\n",a);
        while(1);
 //		exit(0);       
    }else //子进程
    {
        pd1 = getpid();
        pd2 = getppid();
        printf(" i am son\n");
        printf("son 返回进程号==%d\n",pd);
        printf("son 自己的进程号==%d\n",pd1);
        printf("son 父亲的进程号==%d\n",pd2);
        a++;
    }
    exit(0);
}

结果:
在这里插入图片描述
清除僵尸进程:
在这里插入图片描述

6.防止出现孤儿进程

进程的等待:
    wait:等待子进程退出才会往下执行
    整个程序会挂起

函数功能:等待任意的子进程结束
函数头文件:
        <sys/types.h>
        <sys/wait.h>
函数原型:
         pid_t wait(int *status);
函数参数:
        给NULL
函数返回值:
    成功返回终止的那个子进程的pid
    失败返回-1
函数功能:等待指定的子进程结束
函数头文件:
        <sys/types.h>
        <sys/wait.h>
函数原型:
    pid_t waitpid(pid_t pid,int * status,int options);
函数参数:
        pid:你要等待的子进程的ID
        status:NULL
        
函数返回值:
    成功返回终止的那个子进程的pid
    失败返回-1

代码:

//测试等待进程的函数(wait)
//防止出现孤儿进程
void test_wait(void)
{
    pid_t pd1,pd2;
    pid_t pd = fork();
    pd1 = getpid();
    pd2 = getppid();
    if(pd > 0)//父进程
    {
        printf("hello i am father\n");
        wait(NULL);//回收子进程
        //防止子进程出现孤儿进程
        printf("father 返回进程号==%d\n",pd);
        printf("father 自己的进程号==%d\n",pd1);
        printf("father 父亲的进程号==%d\n",pd2);
    }else//子进程
    {
        sleep(1);
        printf("i am son\n");
        printf("son 返回进程号==%d\n",pd);
        printf("son 自己的进程号==%d\n",pd1);
        printf("son 父亲的进程号==%d\n",pd2);
    }
    
}

结果:
在这里插入图片描述

7. 进程的死亡清理函数

会注册一个函数
当进程死掉的时候而且是正常死掉会去执行这个函数
函数功能:注册死亡函数
函数头文件:#include <stdlib.h>
函数的原型:int atexit(void (*function)(void));
函数的参数:
            空参空返回值的函数指针
函数返回值:  
            0  成功
            -1 失败

代码:

//测试死亡函数
void test_fcution(void)
{
    printf("i am death function\n");
    exit(0);
}
void Test_atexit(void)
{
    char * str ="hello";
    atexit(test_fcution);//注册死亡函数
    printf("函数注册完毕\n");
    exit(0);
}

结果:
在这里插入图片描述

8.继承函数

execl:
提供机制
当程序将要死亡的时候
调用该函数,会产生一个新的进程
来替代该程序的所有空间资源,包括进程号
提供了从一个进程启动另一个进程

函数API
函数功能:继承一个进程的空间
函数头文件: #include <unistd.h>
函数原型:
    int execl(const char *path, const char *arg, ...);
函数参数:
    path : 你要启动进程可执行的路径
    const char *arg, ...:
        函数的传参,NULL
返回值:成功函数没有返回,出错返回-1

代码:

//测试execl
void Test_execl(void)
{
    pid_t pid =getpid();
    pid_t ppid=getppid();
    printf("正常执行打进程的pid==%d\n",pid);
    printf("正常执行打进程的ppid==%d\n",ppid);
    execlp("ls","NULL",(char *)NULL);
    printf("hello world\n");
}

结果:
在这里插入图片描述

总结

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源分为10份,此为第6份文件,包含以下打印机PPD文件: hp-laserjet_m1005 hp-laserjet_m101-m106 hp-laserjet_m1120_mfp hp-laserjet_m1120n_mfp hp-laserjet_m1319f_mfp hp-laserjet_m1522nf_mfp-pcl3 hp-laserjet_m1537dnf_mfp-pcl3 hp-laserjet_m1538dnf_mfp-pcl3 hp-laserjet_m1539dnf_mfp-pcl3 hp-laserjet_m2727_mfp-pcl3 hp-laserjet_m3027_mfp-pcl3 hp-laserjet_m3035_mfp-pcl3 hp-laserjet_m4345_mfp-pcl3 hp-laserjet_m4349_mfp-pcl3 hp-laserjet_m5025_mfp-pcl3 hp-laserjet_m5035_mfp-pcl3 hp-laserjet_m5039_mfp-pcl3 hp-laserjet_m9040_mfp-pcl3 hp-laserjet_m9050_mfp-pcl3 hp-laserjet_m9059_mfp-pcl3 hp-laserjet_mfp_m129-m134 hp-laserjet_mfp_m28-m31 hp-laserjet_p1005 hp-laserjet_p1006 hp-laserjet_p1007 hp-laserjet_p1008 hp-laserjet_p1009 hp-laserjet_p1505 hp-laserjet_p1505n-zxs hp-laserjet_p2014-zxs hp-laserjet_p2014n-zxs hp-laserjet_p2015_series-pcl3 hp-laserjet_p2015d_series hp-laserjet_p2015dn_series hp-laserjet_p2015n_series hp-laserjet_p2015x_series hp-laserjet_p2035-pcl3 hp-laserjet_p2035n-pcl3 hp-laserjet_p2055-pcl3 hp-laserjet_p2055d-pcl3 hp-laserjet_p2055dn-pcl3 hp-laserjet_p2055x-pcl3 hp-laserjet_p3004-pcl3 hp-laserjet_p3005-pcl3 hp-laserjet_p3010_series-pcl3 hp-laserjet_p4014 hp-laserjet_p4014dn hp-laserjet_p4014n hp-laserjet_p4015 hp-laserjet_p4015dn hp-laserjet_p4015n hp-laserjet_p4015tn hp-laserjet_p4015x hp-laserjet_p4515 hp-laserjet_p4515n hp-laserjet_p4515tn hp-laserjet_p4515x hp-laserjet_p4515xm hp-laserjet_pro_mfp_m125a hp-laserjet_pro_mfp_m125nr hp-laserjet_pro_mfp_m125nw hp-laserjet_pro_mfp_m125r hp-laserjet_pro_mfp_m125rnw hp-laserjet_pro_mfp_m125s hp-laserjet_pro_mfp_m126a hp-laserjet_pro_mfp_m126nw hp-laserjet_pro_mfp_m127fn hp-laserjet_pro_mfp_m127fp hp-laserjet_pro_mfp_m127fs hp-laserjet_pro_mfp_m127fw hp-laserjet_pro_mfp_m128fn hp-laserjet_pro_mfp_m128fp hp-laserjet_pro_mfp_m128fw hp-laserjet_pro_mfp_m25a hp-laserjet_pro_mfp_m25nw hp-laserjet_pro_mfp_m26a hp-laserjet_pro_mfp_m26nw hp-laserjet_pro_mfp_m27c hp-laserjet_pro_mfp_m27cnw hp-laserjet_professional_m1132_mfp

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值