浅谈Linux下进程相关属性和fork()函数

进程:

  • 直观概念:程序的一个执行实例,正在执行的程序等

  • 内核观点:担当分配系统资源(CPU时间,内存)的实体

操作系统是如何管理进程的呢?先把进程描述起来,再把进程组织起来。

  • 描述进程-PCB:进程信息被放在一个叫做程序控制块的数据结构中,可以理解为进程属性的集合。课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct

  • 组织进程:内核采用双向链表来组织task_struct

task_struct部分内容:

进程标识符(PID):别名进程号,在操作系统中不会重复
状态:任务状态,退出代码,退出信号等
优先级:相对于其他进程的优先级
内存指针:指向程序地址空间
程序计数器:保存进程即将要执行的下一条指令的地址
上下文数据:保存上一次执行时,寄存器当中的值
I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表
记账信息:当前进程启动的时间,当前进程占用CPU的时间

程序计数器&&上下文数据 应用实例:

  1. 进程在执行的时候,进程会进行切换,切换是由操作系统调度的
  2. 在被切换出去的时候,该进程中的程序计数器会保存程序要执行的下一条指令,上下文信息会保存寄存器当中的值。
  3. 再次切换回来的时候,通过程序计数器和上下文信息来恢复之前的场景,继续运算

进程状态

运行:正在CPU上面运算
就绪状态:程序已经准备好,在就绪队列中等待CPU资源
阻塞状态:等待I/O就绪

R:运行状态
S:可中断睡眠状态
D:磁盘睡眠状态,不可以被打断
T:暂停状态(可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。)

前台进程:“+”代表前台进程
后台进程:没有“+”代表后台进程

t:跟踪状态---gdb调试程序的时候可以发现程序是t状态
X:死亡状态
Z:僵尸状态

了解了进程状态之后,如何来查看进程的一些属性呢
LInux下我们通过ps aux | grep 程序名来查看一个进程相关信息

//测试代码
#include <stdio.h>
#include <unistd.h>

int main()
{
    while(1)
    {
        //sleep(1);
    }
    return 0;
}

在另一台终端输入ps aux | head -1; ps aux | grep ./test | grep -v grep(分号前面的指令是为了打印标题,后面的指令是用来查看进程信息的,grep -v grep是为了过滤)
不加grep -v
浅谈Linux下进程相关属性和fork()函数
加上后效果
浅谈Linux下进程相关属性和fork()函数
执行指令后我们可以读出进程标识符PID,以及进程状态(为R+)。

加上sleep(1)后,我们可以发现此时进程状态为S+。

浅谈Linux下进程相关属性和fork()函数

那么如何把一个前台进程变为后台进程呢,在可执行程序后加 & 即可。
浅谈Linux下进程相关属性和fork()函数
相信大家在Linux下对 ctrl+c 非常熟悉,不管遇见什么难倒我们的事情,第一件事情就是无脑 ctrl+c,看是否解决问题 /滑稽 。我们可以使用 ctrl+c 关闭任何一个我们想要关闭的前台进程,但是对于后台进程他却无能为力。kill -9 pid可谓linux最强的命令了,只需知道进程的pid就可以杀死这个进程。我们来试试
浅谈Linux下进程相关属性和fork()函数
kill命令能干掉后台进程,可是我们不想这么粗暴,还有其他办法吗?答案是有的:Linux下还有一个 fg 命令,他可以把最后一次放到后台的进程恢复为前台进程。然后就可以用ctrl+c关闭啦
浅谈Linux下进程相关属性和fork()函数
僵尸状态我们在后文赘述。

关于进程的相关信息我们还可以通过ll /proc/进程PID来进行查看,例如查看1号进程打开的文件描述符:ll /proc/1/fd

进程优先级

  • 基本概念:CPU资源分配的先后顺序,就是指进程的优先权
  • 查看:用top命令查看或更改已存在进程的nice值(NI)
  • >先在命令行输入 top

    进入top后按“r”–>输入进程PID–>输入nice值 即可完成NI值修改

  • 计算公式:PR(new) = PR(old) + NI;

PRI && NI辨析

  • > PRI即进程优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小,进程的有限级别越高;NI就是我们所说的nice值,其表示进程可被执行的优先级的修正数值。
  • > PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
  • > 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行所以,调整进程优先级,在Linux下,就是调整进程nice值
  • > nice其取值范围是-20至19,一共40个级别。
  • > 需要注意进程的nice值不是进程的优先级,它们是不同的概念,但是进程的nice值会影响到进程的优先级变化;可以将nice值理解为进程优先级的修正数据

fork()函数

  • 理解:fork()函数从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程
#include <unistd.h>
pid_t fork(void);
//返回值:子进程中返回0,父进程返回子进程id,出错返回-1
  • fork有两个返回值
  • 父子进程之间代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
//测试代码
#include <stdio.h>
#include <unistd.h>

int main()
{
    pid_t ret = fork();
    if(ret < 0)
    {
        //error
        perror("fork error");
        return 0;
    }
    else if(ret > 0)
    {
        //father
        while(1)
        {
            printf("i am father, ret=%d, pid=%d, ppid=%d\n", ret, getpid(), getppid());
            sleep(1);
        }
    }
    else
    {
        //child
        while(1)
        {
            printf("i am child, ret=%d, pid=%d, ppid=%d\n", ret, getpid(), getppid());
            sleep(1);
        }
    }

    return 0;
}

解释:

pid_t getpid(void)     //谁调用返回谁的进程pid
pid_t getppid(void)   //谁调用返回谁的父进程pid

运行结果:
浅谈Linux下进程相关属性和fork()函数

  • 通过返回值的不同可以让父子进程执行不同的代码
  • 通过 ps -ef可以查看进程的pid以及进程父进程的pid,从而确定哪一个进程是父进程,哪一个进程是子进程
  • 通过终端启动的前台程序,父进程是bash(命令行解释器)
  • 一旦创建出子进程后,父进程和子进程就是抢占式执行
    浅谈Linux下进程相关属性和fork()函数

其他相关概念:

  • > 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
  • > 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
  • > 并行:多个进程,每个进程读独占一颗CPU,在同一时间,同时计算各自程序中的代码
  • > 并行:多个进程在同一颗CPU上面运行,每一个进程都独占CPU一小会,操作系统进行进程切换,让每一个进程都能使用CPU

总结:

  • fork()函数是在代码当中创建一个进程
  • 1.调用fork()函数,fork()函数是一个系统调用
  • 2.父进程调用fork()函数,创建子进程,子进程拷贝父进程的PCB(task_struct),父进程和子进程是独立的两个进程
  • 3.子进程从fork函数之后的代码开始运行,通过程序计数器(保存了程序即将要执行的下一条指令)和上下文数据(保存了寄存器当中的值)知道自己如何运行

猜你喜欢

转载自blog.51cto.com/14289099/2622962