(7)Linux基础——进程的含义、创建出的空间和特点、命令、调度方式、状态、函数接口、消亡

一、进程的含义

进程:是操作系统进行资源分配的最小单位。程序动态执行的过程,包括创建、调度、消亡。每启动一个进程,操作系统就会为它分配一块独立的内存空间。每个进程占有一块独立的内存空间,不同的进程不存在共享空间。

二、进程创建出来的空间和其特点

①文本段(文本区)

代码、指令

②数据段(数据区)

字符串常量,未初始化静态变量/全局变量,已初始化静态变量/全局变量

③系统数据段

堆区:程序员手动管理malloc申请,free释放

栈区:操作系统管理

三、进程的命令

①top

根据CPU占用率动态查看进程信息(按q退出)

②ps -ef

查看当前时刻所有进程的信息

③ps -aux

查看当前时刻进程的信息

④pstree

查看进程关系

⑤kill -9 PID

杀死PID对应的进程

1.创建一个正在运行的进程

2.使用ps -ef查看该进程的的PID

例子中运行的PID为25679

3.在终端输入输入kill -9 25679

4.结果:

⑥killall -9 进程名:

杀死进程名对应的所有进程

eg: killaill -9 xxx.c

四、进程调度的方式

1.宏观并行,微观串行

CPU处理事情很快,表面看起来像是一起进行的,实际上这边执行一下,那边再去执行一下

2.内核进程的调度算法

  1. 先来后到

  1. 高优先级调度算法

  1. 时间片轮转调度算法(时间片指的是CPU在某段任务执行的一段时间)

  1. 多级队列反馈调度算法

  1. 负载均衡调度算法

五、进程的状态

1.五状态模型

运行态、就绪态、阻塞态、新建态、退出态

2.七状态模型

R( Running):运行态,就绪态. 这里的R对应模型中的等待状态/运行状态

S (Sleeping):睡眠状态,可唤醒等待态.对应模型中的阻塞状态,他必须等待事件。

D(Disk sleep):深度睡眠状态,不可唤醒等待态。是因为受到内核指示而停用的睡眠进程,外部信号无法唤醒它们,只能有内核来亲自唤醒

T(Topped):暂停状态。进程特意停止运行的状态,比如调试器暂停来进行调试操作的时候。

t(tracing stop):它本来不是一个进程的状态,就是用来区分处在暂停状态的进程,看它是否是被调试的进程还是常规的暂停。

Z(Zombie):僵尸状态。代码执行结束,空间没有被回收

六、进程相关的函数接口

创建头文件

#ifndef __HEAD_H__//防止头文件被重复定义
#define __HEAD_H__//防止头文件被重复定义

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

#endif //防止头文件被重复定义

1.fork

①函数原型:pid_t fork(void);

②功能:创建一个子进程

③参数:缺省

⑤返回值:成功在父进程中返回子进程PID,子进程中返回0 ,失败返回-1

#include "head.h"

int main(int argc, char const *argv[])
{
    pid_t pid;

    pid = fork( );
    if(-1 == pid)
    {
        perror("fail to fork");
        return -1;
    }

    if(0 == pid)
    {
        printf("我是子进程\n");
    }

    if(0 <  pid)
    {
        printf("我是父进程\n");
    }

    return 0;
}

运行结果:

2.getpid

①函数原型:pid_t getpid(void);

②功能:获得调用该函数的进程的PID

③参数:缺省

#include "head.h"

int main(int argc, char const *argv[])
{
    pid_t pid;

    pid = fork( );
    if(-1 == pid)
    {
        perror("fail to fork");
        return -1;
    }

    if(0 == pid)
    {
        printf("我是子进程PID = %d",getpid());
    }

    if(0 <  pid)
    {
        printf("我是父进程PID=%d  我的子进程PID= %d\n",getpid(),pid);
    }

    return 0;
}

输出结果:

3.getppid

①函数原型:pid_t getppid(void);

②功能:获得调用该函数父进程的PID

③参数:缺省

#include "head.h"

int main(int argc, char const *argv[])
{
    pid_t pid;

    pid = fork( );
    if(-1 == pid)
    {
        perror("fail to fork");
        return -1;
    }

    if(0 == pid)
    {
        printf("我是子进程PID = %d 我的父进程PID=%d\n",getpid(),getppid());
    }

    if(0 <  pid)
    {
        printf("我是父进程PID=%d  我的子进程PID= %d\n",getpid(),pid);
    }

    return 0;
}

输出结果:

4.exit

①函数原型:void exit(int status);

②功能:进程退出

③参数:status:进程结束的状态

⑤返回值:缺省

#include "head.h"

int main(int argc, char const *argv[])
{
    printf("hello world\n");//有没有/n,hello world都可以输出
    exit(0);
    printf("how are you\n");

    return 0;
}

输出结果:只输出上面的hello world ,因为exit已经将进程结束

5._exit

①函数原型:void _exit(int status);

②功能:直接使进程停止运行,清除其使用的内存空间,并清除其在内核的各种数据结构。

③参数:status:进程结束的状态

⑤返回值:缺省

_exit()  —— 直接结束进程进入到内核中

exit()  —— 清理I/O缓冲区后再退出进程

#include "head.h"

int main(int argc, char const *argv[])
{
    printf("hello world");//注意:这里没有\n,如果添加\n是可以输出来的
    _exit(0);
    printf("how are you\n");

    return 0;
}

输出结果:什么都没有输出

6.exec函数族

①函数原型:

extern char **environ;

int execl(const char *path, const char *arg, ...

/* (char *) NULL */);

int execlp(const char *file, const char *arg, ...

/* (char *) NULL */);利用进程空间执行一个系统命令

int execle(const char *path, const char *arg, ...

/*, (char *) NULL, char * const envp[] */);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execvpe(const char *file, char *const argv[],

char *const envp[]);

②功能:利用进程空间执行一段新的代码

l:参数以列表形式传递

p:在系统路径下查找文件

e:执行新代码时,更新环境变量

v:参数以指针数组形式传递

⑤返回值:失败返回-1

7.getenv

①函数原型:char *getenv(const char *name);

②功能:获得环境变量name对应的值

③参数:name:环境变量名

⑤返回值:成功返回环境变量对应的值,失败返回NULL

8.setenv

①函数原型:int setenv(const char *name, const char *value, int overwrite);

②功能:设置环境变量的值

③参数:

name:环境变量名

value:环境变量的值

overwrite:

0值:如果变量名存在不会替换旧值

非0值 :如果变量名存在会替换旧值

⑤返回值:成功返回0 ,失败返回-1

9.system

①函数原型: int system(const char *command);

②功能:执行一条command shell命令 (minishell中可以用到)

#include "head.h"

int main(int argc, char const *argv[])
{
    char ch[4096] = {0};

    gets(ch);
    system(ch);
    return 0;
}

输出结果:

七、进程的消亡

  1. 僵尸进程

①父进程先结束,子进程会成为孤儿进程,被系统进程收养,子进程再结束,被系统进程回收空间。

②父进程在进程结束时回收子进程空间

  1. wait

wait具有阻塞功能

①函数原型:pid_t wait(int *wstatus);

②功能:回收子进程空间

③参数:wstatus:存放子进程结束状态空间首地址

④返回值:成功返回回收到子进程的ID,失败返回-1

⑤作用:回收子进程空间,具有同步功能

WIFEXITED(wstatus):判断是否正常结束

WEXITSTATUS(wstatus):获得正常结束时返回的值

WIFSIGNALED(wstatus):判断是否被信号杀死(eg:kill -9)

WTERMSIG(wstatus):获得杀死进程任务的信号编号

1.正常结束:

#include "head.h"

int main(int argc, char const *argv[])
{
    pid_t pid;
    pid_t ret;
    int status;

    pid = fork();
    if(-1 == pid)
    {
        perror("fail to fork");
        return -1;
    }

    if(0 == pid)
    {
        printf("子进程:PID%d,PPID%d\n",getpid(),getppid());
        sleep(5);//让子进程睡5s
        printf("子进程睡醒了\n");
        exit(1);
    }


    else if (pid > 0)
    {
        printf("父进程 PID:%d\n", getpid());
        ret = wait(&status);
        if (WIFEXITED(status))
        {
            printf("是否为正常死亡%d\n", WEXITSTATUS(status));
        }
        else if (WIFSIGNALED(status))
        {
            printf("杀死他的信号为:%d\n", WTERMSIG(status));
        }
    }

    return 0;
}

输出结果:(正常死亡结果为1)

2.被信号杀死:

#include "head.h"

int main(int argc, char const *argv[])
{
    pid_t pid;
    pid_t ret;
    int status;

    pid = fork();
    if(-1 == pid)
    {
        perror("fail to fork");
        return -1;
    }

    if(0 == pid)
    {
        printf("子进程:PID%d,PPID%d\n",getpid(),getppid());
        sleep(15);//让子进程睡15
        printf("子进程睡醒了\n");
        exit(1);
    }


    else if (pid > 0)
    {
        printf("父进程 PID:%d\n", getpid());
        ret = wait(&status);
        if (WIFEXITED(status))
        {
            printf("是否为正常死亡%d\n", WEXITSTATUS(status));
        }
        else if (WIFSIGNALED(status))
        {
            printf("杀死他的信号为:%d\n", WTERMSIG(status));
        }
    }

    return 0;
}

输注结果:

3.waitpid

wait(NULL) 等价于 waitpid(-1, NULL, 0)

①函数原型:pid_t waitpid(pid_t pid, int *wstatus, int options);

②功能:回收子进程空间

③参数:

pid:想要回收的子进程空间对应的PID(-1回收任意一个子进程空间)

wstatus:存放进程状态空间首地址

options:

0:阻塞回收子进程空间

WNOHANG:非阻塞回收子进程空间

④返回值:成功返回回收到的子进程空间,失败返回-1 ,非阻塞形式没有回收到子进程空间返回0

#include "head.h"

int main(int argc, char const *argv[])
{
    pid_t pid;
    pid_t ret;
    int status;

    pid = fork();
    if (-1 == pid)
    {
        perror("fail to fork");
        return -1;
    }
    if (0 == pid)
    {
        printf("子进程开始执行:  PID:%d, PPID:%d\n", getpid(), getppid());
        sleep(5);
        printf("子进程即将退出!\n");
        exit(0);
    }
    else if (pid > 0)
    {
        printf("父进程开始执行:  PID:%d\n", getpid());
        while ((ret = waitpid(pid, &status, WNOHANG)) == 0)
        {
            printf("子进程还没结束,我先干会别的!\n");
            sleep(1);
        }

        printf("回收到子进程(PID:%d)空间\n", ret);
        if (WIFEXITED(status))
        {
            printf("子进程正常结束,值为:%d\n", WEXITSTATUS(status));
        }
        else if (WIFSIGNALED(status))
        {
            printf("子进程被 %d 信号杀死\n", WTERMSIG(status));
        }    
    }

    return 0;
}

输出结果:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值