【Linux】从零开始认识进程 — 中篇

这篇具有很好参考价值的文章主要介绍了【Linux】从零开始认识进程 — 中篇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【Linux】从零开始认识进程 — 中篇,一起学Linux吧!,linux,运维,服务器,c++,算法,学习
今天我们继续学习进程,首先送给大家一句话:

如果痛恨所处的黑暗,请你成为你想要的光。 —— 顾城

1 认识进程收尾

进程的路径是可以改变的, 每个进程在启动的时候,会记录自己当前在哪个路径下启动。

我们可以使用fopen ("log.txt",“w”)来进行使用,该函数会在路径下创建一个新文件log.txt。即可验证进程所处路径:

  1 #include<stdio.h>
  2 
  3 int main(){
  4   FILE* fp = fopen("log.txt","w");
  5   (void)fp;//防止报错
  6                                                                                                                                                                               
  7   return 0;
  8 }

我们编译运行之后,就可以发现当前路径下创建了一个新文件log.txt。
【Linux】从零开始认识进程 — 中篇,一起学Linux吧!,linux,运维,服务器,c++,算法,学习
那我们可不可以改变一下进程的路径呢,当然可以,使用int chdir(const char* path)就可以实现改变进程路径的功能.
我们来试一试,通用通过代码来测试一下:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 
  5 int main(){
  6 
  7   chdir("/home/jlx/lesson12");
  8 
  9   FILE* fp = fopen("log.txt","w");
 10   (void)fp;
 11 
 12   while(1){
 13     printf("I am a process,pid: %d\n",getpid());                                                                                                                              
 14     sleep(1);
 15   }
 16 
 17   return 0;
 18 }

接下来我们来观察一下:
【Linux】从零开始认识进程 — 中篇,一起学Linux吧!,linux,运维,服务器,c++,算法,学习
在lesson12路径下也成功创建了新文件log.txt。所以我可以更改进程的工作路径,默认是在可执行程序的路径下。

2 进程状态

2.1 谈谈Linux进程状态

进程状态是task_struct内部的一个属性,int status就是一个代表状态的数字。
看看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):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

接下来我们来验证一下这些状态(D状态无法验证,X状态无法验证)

R 、T、 D状态

写个程序来进行测试:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7   while(1)
  8   {                                                                                
  9     printf("I am a process,pid : %d\n",getpid());//注意这里没有写sleep函数
 10   }
 11 
 12   return 0;
 13 }

使用while : ;do ps ajx | head -1&& ps ajx | grep testStatus |grep -v grep ;sleep 1 ;done指令进行实时监控:
【Linux】从零开始认识进程 — 中篇,一起学Linux吧!,linux,运维,服务器,c++,算法,学习
可以看到我们右边的可执行程序一致在运行,可是在左边的监控中,却发现是S+状态???这是为什么怎么会是休眠状态(sleep),明明一直在运行啊!?
我们来把printf去掉,再来看看怎么样

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7   while(1)
  8   {                                                                                
  9     //printf("I am a process,pid : %d\n",getpid());//注意这里没有写sleep函数
 10   }
 11 
 12   return 0;
 13 }

来看运行的效果:
【Linux】从零开始认识进程 — 中篇,一起学Linux吧!,linux,运维,服务器,c++,算法,学习
唉?!怎么现在成了R+状态了???怎么现在就是运行状态了???
这个问题到底是怎么一回事儿???
其实这与printf有关,printf的本质是往外设显示器上打印,但是进程是在云服务的cpu上运行的。根据冯诺依曼体系结构,外设的处理速度要远远小于cpu,所以在显示器的打印过程中,cpu就在等待显示器设备打印就绪(也变相证明了cpu运行速度比显示器快的多的多的多!!!)

通过刚刚的证明,说明了:

  1. S 休眠状态就是CPU在等待“资源”就绪。
  2. 该休眠成为可中断睡眠,随时可以被外界唤醒。
    • 代表子啊前台运行,在./ 可执行程序 后加&会在后台运行,就不带加号了。

在来看暂停状态 : T(让进程先暂停,等待被唤醒)
使用 kill 命令可以进程发信号,kill具有以下信号(宏定义信号):

 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

其中的 -19 可以完成暂停 -18 可以让暂停状态继续运行。
来看演示:
【Linux】从零开始认识进程 — 中篇,一起学Linux吧!,linux,运维,服务器,c++,算法,学习
这样直观就可以看到暂停状态了。
这个 t 暂停状态多在gdb调试里常见,我们俗称的断点就是做到使进程暂停的作用。即调试暂停
感兴趣可以自行查看哦。

D 状态
这个状态也叫也叫不可中断睡眠状态,是内存为了保护数据不得不采取的删除进程操作,一般不会遇见。

2.2 僵尸进程和孤儿进程

接下来我们来了解僵尸进程和孤儿进程。

Z(zombie)-僵尸进程

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

这个状态类似有人受害,被抛尸荒野,警察一定会封锁现场,法医进行甄别,最后是家属来准备后事。
所以进程也需要有人来把他收走,准备后事。
我们写一段代码来看看:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7   pid_t id = fork();
  8   if(id == 0)
  9   {
 10     int cnt = 5;
 11     while(cnt--)
 12     {
 13       printf("I am child,cnt: %d ,pid: %d \n",cnt,getpid());                       
 14       sleep(1);
 15     }
 16   }
 17   else
 18   {
 19     while(1)
 20     {
 21       printf("I am parent,running always,pid: %d\n",getpid());
 22       sleep(1);
 23     }
 24   }
 25 }

这个代码子进程运行五次就会停止,让我们看看效果:
【Linux】从零开始认识进程 — 中篇,一起学Linux吧!,linux,运维,服务器,c++,算法,学习
当cnt小于0时,就结束了进程,于是子进程就成为了僵尸进程。依然就要PID但是不在进行运行。
其中的<defunct>表示被抛弃的,不运行的。
僵尸进程就是:已经运行完毕,但是需要维持自己的退出信息,在自己的进程task_struct中记录自己的信息,未来让父进程来进行读取。如果没有父进程进行读取,僵尸进程会一直存在(会引起内存泄漏问题)

僵尸进程危害

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

孤儿进程

再来看孤儿进程(与僵尸进程相反,孤儿进程是父进程运行完毕了):

  • 父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
  • 父进程先退出,子进程就称之为“孤儿进程”
  • 孤儿进程被1号init进程领养,当然要有init进程回收喽

这个就类似孤儿,我们写代码来测试一下:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7   pid_t id = fork();
  8   if(id == 0)
  9   {
 10     
 11     while(1)
 12     {
 13       printf("I am child,running always,pid: %d \n",getpid());
 14       sleep(1);                                 
 15     }
 16   }
 17   else
 18   {
 19     int cnt = 5;
 20     while(cnt--)
 21     {
 22       printf("I am parent,cnt:%d,pid: %d\n",cnt,getpid());                         
 23       sleep(1);                                                                 
 24     }                                                                           
 25   }                                                                                                                                                      
 26 }                                                                               

这个代码父进程运行五次就会停止,让我们看看效果:
【Linux】从零开始认识进程 — 中篇,一起学Linux吧!,linux,运维,服务器,c++,算法,学习
这样子进程就变成了孤儿进程STAT。
孤儿进程在运行结束后,会被1号进程(操作系统本身)进行领养,保证子进程正常被回收!

2.3 浅谈进程的阻塞、挂起和运行

【Linux】从零开始认识进程 — 中篇,一起学Linux吧!,linux,运维,服务器,c++,算法,学习
这个是操作系统的宏观理论(指导思想),对于任意一门操作系统都适用!!!

  1. 而进程会在运行队列中,该进程的状态就是R状态!!!也就是图中的就绪状态。
  2. 在CPU中进程会按时间片轮转调度(比如每2ms更换运算的进程),让多个进程以切换的方式进行调度,在一个时间段中得以推进代码,就叫做并发!!!
  3. 在任何时刻,都同时有多个进程在同时运行,就叫做并行!!!
  4. 那什么是阻塞态呢???
    就是将其列入设备的等待队列中(比如scanf 等待j键盘输入),完成会回返回运行队列,唤醒。这就是等待队列
  5. 什么是挂起态呢???
    挂起态,是一个表示进程被停滞的特殊状态。在此状态下,进程不会在主存中活跃,而是被转移到辅助存储器(如硬盘 的 swap)中。这 意味着进程在此状态下不会获得CPU的执行时间,并从运行队列中移除,也就被挂起到外设当中了!!!这是一种效率换取空间的办法。

送给我们一句话:

如果痛恨所处的黑暗,请你成为你想要的光。 —— 顾城文章来源地址https://www.toymoban.com/news/detail-842389.html

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

到了这里,关于【Linux】从零开始认识进程 — 中篇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 从零开始学习Linux运维,成为IT领域翘楚(九)

    Service命令 服务(service) 本质就是进程,但是是运行在后台的,通常都会监听某个端口,等待其它程序的请求,比如(mysql , sshd 防火墙等),因此我们又称为守护进程。 语法: 注意: 示例1 查看当前防火墙的状况,关闭防火墙和重启防火墙。 Systemd命令 Linux的启动一直采用init进

    2024年02月03日
    浏览(52)
  • 【Linux】从零认识文件操作

    送给大家一句话: 要相信,所有的不美好都是为了迎接美好,所有的困难都会为努力让道。 —— 简蔓《巧克力色微凉青春》 在C语言已经掌握文件操作的一些接口,接下来我们来从操作系统的层面来理解文件操作!!! 基础IO的篇章我们将讲解以下内容: 复习C文件IO相关操

    2024年04月10日
    浏览(33)
  • Linux进程的认识

    查看进程指令proc/ps/top 注意哦, 我们经常使用的指令, 像ls, touch…这些指令在启动之后本质上也是进程 proc 是内存文件系统, 存放着当前系统的实时进程信息. 每一个进程在系统中, 都会存在一个唯一的标识符(pid - process id), 就如同学生在学校里有一个专门的学号一样. 大多数进

    2024年02月15日
    浏览(78)
  • 跟我一起从零开始学python(十)Hadoop从零开始入门

    回顾之前讲了python语法编程 ,必修入门基础和网络编程,多线程/多进程/协程等方面的内容,后续讲到了数据库编程篇MySQL,Redis,MongoDB篇,和机器学习,全栈开发,数据分析前面没看的也不用往前翻,系列文已经整理好了: 1.跟我一起从零开始学python(一)编程语法必修

    2024年02月11日
    浏览(39)
  • 【Linux】第八讲:Linux进程信号详解(一)_ 认识信号 | 产生信号

    「前言」文章是关于Linux进程信号方面的知识,本文的内容是Linux进程信号第一讲,讲解会比较细,下面开始! 「归属专栏」Linux系统编程 「主页链接」个人主页 「笔者」枫叶先生(fy)  「枫叶先生有点文青病」「每篇一句」  人生天地间,忽如远行客。 ——《乐府·青青陵上

    2023年04月25日
    浏览(47)
  • 【Linux】从零开始学习Linux基本指令(三)

    🚩 纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:Linux入门 🔥该文章主要了解Linux操作系统下的基本指令。 ⚡️该篇为Linux指令部分的终章,如果您想了解前两篇文章的内容,可以在阅读本文后点击👉【Linux】从零开始学习Linux基本指令(一) 和 【Linux】从零

    2024年02月08日
    浏览(45)
  • 【Linux】从零开始学习Linux基本指令(二)

    🚩 纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:Linux入门 🔥该文章主要了解Linux操作系统下的基本指令。 ⚡️上一篇可以看这里 👉【Linux】从零开始学习Linux基本指令(一) 了解更多。 语法 :man [选项] [命令] 功能 :可以访问Linux手册页,查看Linux中的指

    2024年02月08日
    浏览(46)
  • 【Linux】从零开始学习Linux基本指令(一)

    🚩 纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:Linux入门 🔥该文章主要了解Linux操作系统下的基本指令。  在计算机发展过程中,先出现的是指令,后来才有了图形化界面。指令操作和图形化界面操作在 本质上是相同的 ,都是用户与操作系统交互的方

    2024年02月08日
    浏览(44)
  • 【Linux】开始学习进程替换吧!

    送给大家一句话: 人生中有些事,你不竭尽所能去做,你永远不知道你自己有多出色。—— 尾田荣一郎《海贼王》 通过学习进程替换,我们可以体会到多语言混搭的快乐,可以从C语言直接蹦到python ,也可以从c++里运行java代码。是不是很厉害!这是通过调度多个进程的效果,

    2024年04月09日
    浏览(42)
  • 【Linux】开始掌握进程控制吧!

    送给大家一句话: 我并不期待人生可以一直过得很顺利,但我希望碰到人生难关的时候,自己可以是它的对手。—— 加缪 通过对进程的学习,我们对虚拟地址,页表,物理地址有了大概认识。我们平时使用的地址都是虚拟地址,通过页表可以访问物理地址(统一的视角进行

    2024年04月10日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包