【操作系统】Linux进阶必须掌握的进程、线程及调度算法~进程学习

Linux内核源代码中,进程的状态是用数字来表示的,为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里面,进程有时候也叫任务)
/*

  • The task state array is a strange “bitmap” of
  • reasons to sleep. Thus “running” is zero, and
  • you can test for combinations of others with
  • simple bit tests.
    /
    static const char * const task_state_array[] = {
    “R (running)”, /
    0 /
    “S (sleeping)”, /
    1 /
    “D (disk sleep)”, /
    2 /
    “T (stopped)”, /
    4 /
    “t (tracing stop)”, /
    8 /
    “X (dead)”, /
    16 /
    “Z (zombie)”, /
    32 */
    };
    面这张图片展示了进程状态之间的关系,现在我们完全不知道这是什么东西!我们接下来逐一分析。
    在这里插入图片描述
    R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
    S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡(interruptible sleep))。
    D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
    T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
    X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

1. 进程各状态的概念

1.1 R-运行态(running)

运行态是进程正在CPU上运行,还是进程只要在运行队列中就叫做运行态呢?
答:所谓的运行态,是只要在运行队列中就叫做运行态,代表我已经准备好了,随时可以被调度!
在这里插入图片描述

1.2 终止状态(stopped)

终止状态是这个进程已经被释放,就叫做终止态?还是该进程还在,只不过永远不运行了,随时等待被释放?
答:进程还在,只不过不运行。

此时,我们想问,进程都终止了,为什么不立马释放对应的资源吗,而要维护一个终止态??
答:我们要释放进程需要花费时间,有没有可能,当前操作系统很忙呢。

1.3 运行阻塞

一个进程使用资源的时候,可不仅仅是在申请CPU资源!‘
进程可能申请更多的其他资源:磁盘,网卡,显卡,显示器资源,声卡/音响
如果我们申请CPU资源,暂时无法得到满足,需要排队的–运行队列

那么如果我们申请其他慢设备的资源呢? — 也是需要排队的!(tast_struct在进程排队)

当进程访问某些资源(磁盘,网卡),该资源如果暂时没有准备好,或者正在给其他进程提供服务,此时:1.当前进程要从runqueue中移除;当前进程放入对应设备的描述结构体中的等待队列!(wait_queue)

当我们的进程此时在等待外部资源的时候,该进程的代码不会被执行,此时进程处于的状态叫做进程阻塞。

阻塞是一种临时状态。

1.4 运行挂起

之前我们提到过,代码是存放在磁盘中的,当运行程序时,先将程序加载到内存,那么当内存不足了怎么办?
当内存不足的时候,操作系统会将该进程的代码进行辗转腾挪,如何辗转腾挪–短期内不会被调度的进程,他的代码和数据依然在内存中!就是在白白浪费空间!操作系统就会把该进程的代码和数据置换到磁盘上!此时被暂时置换到磁盘上的进程就叫做进程挂起。
在这里插入图片描述

2.Linux 进程状态

2.1 R运行状态

R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。


#include <stdio.h>
#include <unistd.h>
int main()
{
	while(1)
	{
		printf("这是一个进程  %d\n",getpid());
		sleep(1);
	}
	return 0;

(base) [jianming_ge@localhost ~]$ ps ajx | head -1 && ps ajx | grep "rrr" | grep                                      -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
20470 29827 29827 20470 pts/7    29827 S+    1002   0:21 ./rrr.o

在这里插入图片描述
发现运行的进程怎么是S呢? 这是因为printf函数太快了,而显示器显示速度太慢啦,因此这个进程看似实在死循环,其实大多数时间都在等待显示器。那么怎么才能进入运行态呢,我们屏蔽掉printf函数,只保留while循环再次进行查看发现已经处于运行态了。
在这里插入图片描述

2.2 S 睡眠状态

s对应的状态一般叫做阻塞状态!
如何把睡眠状态叫醒呢?只需要把进程状态从S睡眠态转换成R运行态即可。
我们常常把S状态叫做浅度睡眠(也叫做可中断睡眠),浅度睡眠可以被唤醒或者杀掉他。

在这里插入图片描述

2.3 Z 和 X 状态

X(dead)状态就是所谓的死亡状态。

Z(zombie)状态是僵尸状态。Z状态是一种已经死亡的状态,但是死了之后,不要让操作系统释放它。那该状态存在的意义是什么呢?当一个Linux中的进程退出的时候,一般不会直接进入X状态(死亡,资源可以立马回收),而是进入Z状态,为什么?

因为进程被创建出来一定是要有任务完成,当进程退出的时候,我们怎么知道进程把任务给我们完成了呢?需要将进程的执行结果告知给父进程或者操作系统。

子进程退出,维护Z状态,就是为了让父进程或者操作系统来读取执行结果!父进程和操作系统通过进程等待来读取僵尸进程的信息。下图是内核源码中的退出信息。
在这里插入图片描述

模拟僵尸进程?

创建子进程,子进程退出了,父进程不退出,也不等待子进程,子进程退出之后所处的状态就是僵尸状态。我们写一段代码来模拟一下!

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(){
    pid_t id = fork();
    if(id==0){
        // 子进程
        // child
        int cnt = 5;
        while(cnt)
        {
            printf("我是子进程,我还剩%dS\n",cnt--);
            sleep(1);
        }
        printf("我是子进程,我已经僵尸了,等待被监测\n");
        exit(0);
    }else{
        // 父进程
        while(1)
        {
            sleep(1);
        }
    }
    return 0;

}

/***
while :; do ps ajx | head -1 && ps ajx | grep 'ddd'|grep -v grep; 
sleep 1; echo"#########################################################";done
***/

在这里插入图片描述
我们发现一开始当子进程还没有僵尸的时候,父子进程都处于S状态,当子进程僵尸时,我们发现此时子进程的状态变成了Z状态。
僵尸状态后 表示死者,死亡之意。

长时间僵尸,有什么问题呢?

如果没有人回收子进程的僵尸,该状态会一直维护!该进程的相关资源(tast_struct)不会被释放!会造成内存泄漏,因此一般必须要求父进程进行回收。

我们再谈谈与之相关的孤儿进程。

在我们们刚刚的代码中,子进程先退出,而父进程一直存在,那如果父进程先退出,子进程一直存在,此时子进程的父进程已经被回收了,子进程没有了父进程,我们把这种子进程处于的状态叫做孤儿进程。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
  pid_t id = fork();
  if(id == 0)
  {
    //child
    int cnt = 5;
    while(1)
    {
      printf("我是子进程,我还剩%dS\n",cnt--);
      sleep(1);
    }
    printf("我是子进程,我已经僵尸了,等待被检测\n");
    exit(0);
  }
  else
  {
    //f
    int cnt = 3;
    while(cnt--)
    {
      sleep(1);
    }
  }
 
  return 0;
}

大约执行3秒过后,我们发现父进程不见了,之间子进程了,此时子进程就是孤儿进程,那么孤儿进程要被1号进程领养。这个1号进程就是操作系统。

在这里插入图片描述
我们发现子进程状态原先是S+,而后面为什么变成了S呢?并且这段代码不能被ctrl +c强制终止了
其中带+号表示这个进程是前台进程,而前台进程能够被ctrl C的,而不带+的被称为后台进程,我们要终止这个代码,输入kill -9 pid即可杀掉。

2.5 T状态

在上面我们看到暂停状态有T和t两种状态,这两种状态都叫暂停状态,这两种状态没有特别大的区别,而有一种特殊情况对应着t状态。

暂停状态就是让运行的进程暂停一下,这个暂停状态可以理解为我们下载一个东西,我们让他暂停一下;在看视频的时候,暂停了一下。此时这个进程就处于暂停状态。
我们在Linux下模拟一下暂停状态,首先写一段死循环程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
  while(1)
  {
    printf("hello\n");
    sleep(1);
  }
}

当程序运行起来时,我们输入

kill -19 pid

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
而t状态时,当我们使用gdb调试代码时,打上断点后,我们r起来,我们发现了t状态,t表示tracing,表示追踪的意思,当进程被调试的时候,遇到断点所处的状态就是t状态!
在这里插入图片描述

3. 其它

cpulimit 就是不断地把它xx 在running 在两个状态切换。

  1. cpulimit
    cpulimit是一个用于限制进程CPU使用率的工具。它使用cgroups进行管理。
    在这里插入图片描述
main()
{
	while(1);
}

常驻进程的死循环,一直占用100%的cpu。那么我们不像让他占用cpu这么多,所以需要cpulimit来限制它

要在CentOS 7上安装cpulimit,请遵循以下步骤:

  1. 打开终端并使用root用户登录系统。

  2. 运行以下命令以更新系统软件包:

    yum update
    
  3. 安装EPEL存储库。运行以下命令:

    yum install epel-release
    
  4. 安装cpulimit。运行以下命令:

    yum install cpulimit
    
  5. 验证cpulimit是否已成功安装。运行以下命令:

    cpulimit --version
    

此命令应该返回cpulimit的版本信息,表示已成功安装。


(base) [jianming_ge@localhost ~]$ climit 20509
-bash: climit: 未找到命令
(base) [jianming_ge@localhost ~]$ cpulimit 20509
Error: You must specify a cpu limit percentage
Usage: cpulimit [OPTIONS...] TARGET
   OPTIONS
      -l, --limit=N          percentage of cpu allowed from 0 to 3200 (required)
      -v, --verbose          show control statistics
      -z, --lazy             exit if there is no target process, or if it dies
      -i, --include-children limit also the children processes
      -h, --help             display this help and exit
   TARGET must be exactly one of these:
      -p, --pid=N            pid of the process (implies -z)
      -e, --exe=FILE         name of the executable program file or path name
      COMMAND [ARGS]         run this command and limit it (implies -z)

Report bugs to <marlonx80@hotmail.com>.
(base) [jianming_ge@localhost ~]$ cpulimit -p 20509
Error: You must specify a cpu limit percentage
Usage: cpulimit [OPTIONS...] TARGET
   OPTIONS
      -l, --limit=N          percentage of cpu allowed from 0 to 3200 (required)
      -v, --verbose          show control statistics
      -z, --lazy             exit if there is no target process, or if it dies
      -i, --include-children limit also the children processes
      -h, --help             display this help and exit
   TARGET must be exactly one of these:
      -p, --pid=N            pid of the process (implies -z)
      -e, --exe=FILE         name of the executable program file or path name
      COMMAND [ARGS]         run this command and limit it (implies -z)

Report bugs to <marlonx80@hotmail.com>.
(base) [jianming_ge@localhost ~]$ cpulimit -p 20509 -l 40
Process 20509 found

(base) [jianming_ge@localhost ~]$ cpulimit -p 15452 -l 40

在这里插入图片描述

通过这个命令,就把它限制到了40%,其实就是不断的ctrl+z, fg 实现的!!
2. 僵尸进程

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

int main(void)
{
    pid_t pid,wait_pid;
    int status;
    printf("hello world!!!!");
    if (pid==-1){
        perror("cannot create new process");
        exit(1);
    } else if(pid==0){
        printf("a\n");
        return 2;
    } else {
        printf("b\n");
    }
    printf("c\n");
    while(1);
    return 1;

}

这段代码中添加了进程的创建和等待,父进程创建了一个新进程并打印输出 ‘b’,子进程打印输出 ‘a’,然后父进程和子进程都打印输出 ‘c’,并进入了一个死循环,没有正常结束程序的方式。程序中中途没有调用 wait 等待子进程结束,因此子进程的结束状态无法得知,会变成一个僵尸进程。
pid==0 返回的是子进程 else 返回的是父进程

(base) [jianming_ge@localhost process-courses]$ ps aux | grep fork2
jianmin+ 28999 92.9  0.0   4216   356 pts/7    R+   15:59   0:10 ./fork2.o
jianmin+ 29000  0.0  0.0      0     0 pts/7    Z+   15:59   0:00 [fork2.o] <defunct>
jianmin+ 29088  0.0  0.0 112828   992 pts/2    S+   15:59   0:00 grep --color=auto fork2

ref:https://blog.csdn.net/qq_58325487/article/details/126997978

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值