草庐IT

[Linux打怪升级之路]-进程的状态

小蜗牛~向前冲 2024-05-03 原文

前言

作者:小蜗牛向前冲

名言:我可以接受失败,但我不能接受放弃

如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。

目录

一、操作系统下进程的状态

1、进程状态的分类

二、Linux下的进程状态

三、僵尸进程和和孤儿进程

1、僵尸进程

2、孤儿进程 

四、进程优先级 

1、基本概念

 2、PRI and NI

3、其他的概念


本期学习目标:理解操作系统下进程状态,Linunx下进程状态,认识僵尸进程和孤儿进程及进程的优先级和进程切换。

在学习进程状态的之前,我们先简单复习一下,什么是进程:进程其实就相当于进程控制模块(pcb)加上磁盘上的可执行程序。

一、操作系统下进程的状态

1、进程状态的分类

对于一个操作系统来说,他其实会有非常多种状态,但是最常见的还是就绪、执行、阻塞。

  • 就绪:当进程已经分配好除CPU外的所以资源,只要再获取CPU后就能够马上运行。
  • 执行:进程已经获得CPU,其程序正在被执行
  • 阻塞:正在执行的进程由于发生某事件而暂时无法继续执行时,便放弃CPU而处于暂停状态,亦即进程的执行受到阻塞,把这种暂停状态称为阻塞状态,有时也称为等待状态或封锁状态。比如进程当中调用wait()函数,会使得进程进入到阻塞状态。

  但是为了满足一些操作系统的需求,就又出现了一些其他的状态:挂起状态、创建状态、终止状态。

 对于挂起状态他是一种特殊的请求,下面简单聊聊为什么要有挂起状态:

(1) 终端用户的请求。当终端用户在自己的程序运行期间发现有可疑问题时,希望暂时使自己的程序静止下来。

(2) 父进程请求。有时父进程希望挂起自己的某个子进程,以便考查和修改该子进程,或者协调各子进程间的活动。

(3) 负荷调节的需要。当实时系统中的工作负荷较重,已可能影响到对实时任务的控制时,可由系统把一些不重要的进程挂起,以保证系统能正常运行。

(4) 操作系统的需要。操作系统有时希望挂起某些进程,以便检查运行中的资源使用情况或进行记账

而对于其他的二种状态: 

  • 创建状态:为一个新进程创建PCB(进程控制块,它是系统为了管理进程设置的一个专门的数据结构,主要表示进程的状态),把该进程转入到就绪状态并插入到就绪队列之中。
  • 终止状态:等待操作系统进行善后处理,然后将其PCB清零,并将PCB空间返还系统

二、Linux下的进程状态

前面我们说的哪些状态是所以操作系统进程状态的统称,下面我们来看看Linux这些状态是如何体现的;为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在 Linux内核里,进程有时候也叫做任务)。 下面的状态在kernel源代码里定义:

/*
* 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):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

进程状态查看:

ps ajx | head -1 && ps ajx | grep 'test'

  由于在test.c文件中我们是用fork创建子进程的,也就是说在fork函数运行前只有父进程,而运行后就既有子进程也有父进程。我们知道如果进程创建成功,就将0返回回给子进程,将子进程的pid返回给父进程。这里我们就只打印出子进程,并休眠2秒。

这里我们观察到父进程一直在运行,而子进程反而处于休眠状态,这是为什么呢?

其实父子进程都在运行的,由于父进程不需要打印到屏幕中,也将不用调用外设资源。所以就处于运行状态,而子进程要打印到屏幕上,所以要调用外设资源,而CPU的运行速度是远大于外设的,所以cpu就会将子进程移除运行队列进行等待,子进程就进行休眠状态了。

这里我们要注意状态的上的+号,表示进程前台,这式我们在进程在跑的时候,输入指令是没有用的但是可以按ctrl+c强制将进程终止,但是如果我们把进程kill -9(杀死后在运行),+号就会消失,我们也就变成了前台进程,这时候输入指令都是有用处的,但是我们就不能按ctrl+c让进程强制终止。

//暂停进程
kill -19 进程的pid
//进程继续
kill -18 进程的pid


下面我们继续来见一见进程的暂停和启动

那我们能见见死亡进程吗?

//杀死进程
kill -9 进程的pid

 我们可以看到这里怎么没有子进程的状态变成X状态,反而变成了Z状态,这又是个什么状态呢?

其实这是是僵尸状态,下面我们一起来看看僵尸状态吧

三、僵尸进程和和孤儿进程

1、僵尸进程

改进程听起来好奇怪,其实他就是当子进程退出了,而父进程没退出,父进程要接受子进程的各种信息时,子进程存在的一种状态,已经死去了但是基本信息海存在等这父进程用wait()接受。

 这里的test虽然被杀死了,但是我们在进程查看中还是能看到他的运行状态。

僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲) 没有读取到子进程退出的返回代码时就会产生僵死(尸)进程 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。

 僵尸进程危害

  •  进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎 么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话 说,Z状态一直不退出,PCB一直都要维护?是的
  • 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构 对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!就会存在内存泄漏

2、孤儿进程 

上面我们说到子进程退出,还有父进程可以回收子进程的信息,子进程只要维持僵尸状态等父进程来回收就可以了,但是如果父进程先退出了,那子进程退出后处于Z状态又该谁来回收呢?

有的,子进程这时候会被1号init进程(os)领养,在由1号init进程回收。

四、进程优先级 

1、基本概念

  • cpu资源分配的先后顺序,就是指进程的优先权(priority)。
  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
  • 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整 体性能

 我们先输入这个命令认识一下进程优先级:

ps -l

 

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值 

 2、PRI and NI

这里我们要重点关注这二个标识,上面说了PRI他的值越小那么他进程的优先级就会越高,也就说他的进程会被CPU优先跑,而NI只要是可以影响PR从而影响进程的优先级。

总结:

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

那么我们是通过什么来修改优先级的呢?

下面我们就用top命令来修改进程的nice:

当我们输入top + r +输入你要修改进程的pid回车后在输入你要修改nice的值是多少,但是我们输入-100时(这里的top要用sudo提权):

 这里的nice最低就修改为-20,因为我们不可能一直提供进程的优先级,这也要是有一个限度的。

3、其他的概念

  • 竟争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高 效完成任务,更合理竞争相关资源,便具有了优先级。
  • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
  • 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
  • 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为 并发。

这里我们重点来理解进程是怎么在CPU下进程切换的。

我们应该明白一个操作系统不可能就一个进程在跑,但是一CPU是只能一下完成一个工作的,那我们拿window操作系统来举例:我电脑上为什么既可以登QQ、微信、听歌,敲代码。这些我们都可认为是进程,难道这些进程都在跑吗?这显然不是的,那操作系统是如何做到呢?

这就要依靠进程切换了,一个CPU中不仅仅存在在PCB用来管理进程,还存在这大量可见和非可见的寄存器。那这些寄存器有什么用呢?进行对正在运行的进程,取指令、分析指令、执行指令(注意:寄存器中的数据是属于但前进程)

假设操作系统现在有三给进程A,B,C都要跑,CPU会先根据这三个进程的进程优先级,决定那个进程先跑,假设A<B<C,那么C进程就会先跑,CPU中会有一个时间片,当C进程的时间片到了后就会换B进程跑,而且会把A进程跑的信息都会保存到PCB中(暂时可以怎么理解),等下次轮到C进程跑的时候就继续上次的进程,这样就完成了进程的切换,也就是并发。

 

有关[Linux打怪升级之路]-进程的状态的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  3. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  4. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  5. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  6. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

    我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

  7. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  8. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  9. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  10. ruby - 在不使用 RVM 的情况下在 Mac 上卸载和升级 Ruby - 2

    我最近决定从我的系统中卸载RVM。在thispage提出的一些论点说服我:实际上,我的决定是,我根本不想担心Ruby的多个版本。我只想使用1.9.2-p290版本而不用担心其他任何事情。但是,当我在我的Mac上运行ruby--version时,它告诉我我的版本是1.8.7。我四处寻找如何简单地从我的Mac上卸载这个Ruby,但奇怪的是我没有找到任何东西。似乎唯一想卸载Ruby的人运行linux,而使用Mac的每个人都推荐RVM。如何从我的Mac上卸载Ruby1.8.7?我想升级到1.9.2-p290版本,并且我希望我的系统上只有一个版本。 最佳答案

随机推荐