当前位置:   article > 正文

进程相关总结(Linux)_ps ajx

ps ajx

目录

一、进程信息的查看指令

1、ps -ajx:显示正在运行的相关联进程信息(父进程PPID) 

2、ps -aux:显示用户正在运行的进程信息 

3、可以通过管道过滤出你想查看的信息 ps -ajx | grep 要过滤的信息 

二、进程的终止

1、进程的终止方式: 

2、我们可以通过指令:echo $? 来得到已经结束进程的结束状态 。

3、进程的退出方式

三、进程间的切换

1、进程间的状态切换图 如下

2、进程切换: 

四、 进程的创建fork()函数

1、fork()、getpid()、getppid()函数: 

2、fork()函数后新进程的状态:

3、进程创建练习 

五、孤儿进程和僵尸进程

1、孤儿进程: 

2、僵尸进程:(进程死了留着尸体没人回收) 

 3、僵尸进程占用资源怎么样清理? 

六、exec函数族

1、exec函数族的功能:

2、execlp函数 

3、execl函数 

七、wait函数

1、进程回收: 

2、wait函数 

3、wait()练习 

 4.wait函数总结 

八、waitpid函数

1、waitpid函数用法: 

2、waitpid练习 

九、进程相关实例

1、对并行和并发的理解 

2、进程和线程的基本概念 

3、进程与线程的区别 

4、为什么有了进程还要有线程 

5、进程的状态转换 

6、外中断和异常有什么区别 

7、守护进程、僵尸进程和孤儿进程 

8、如何避免僵尸进程 


一、进程信息的查看指令

1、ps -ajx:显示正在运行的相关联进程信息(父进程PPID) 

         查看正在运行进程的信息,只不过是更加详细,如有PID(进程id)、PPID(父进程id)、PGID(进程组id)、SID(会话id) 如下图所示:

 

2、ps -aux:显示用户正在运行的进程信息 

        查看正在运行进程的信息(主要是进程的PID),R运行、S睡眠、I空闲、Z僵尸 如下图所示: 

 

3、可以通过管道过滤出你想查看的信息 ps -ajx | grep 要过滤的信息 

         如:ps -ajx | grep ./main ,如下图所示:

 

二、进程的终止

1、进程的终止方式: 

  • 正常退出(自愿的):程序里面正常退出,如return 0 

  • 错误退出(自愿的):发生错误被我们检查到就自己退出了,如打开一个不存在的文件,会给我们返回一个错误编号,这个时候进程的退出就是错误退出 

  • 严重错误(非自愿的):段错误 

  • 被其他进程杀死(非自愿的):使用kill杀死进程 

2、我们可以通过指令:echo $? 来得到已经结束进程的结束状态 。

        $?  是Linux shell 中的一个内置变量其中保存的是最近一次运行的进程的返回值,这个返回值有以下3种情况: 

1).程序中的main函数运行结束,$? 中保存的是main函数的返回值(注意这个返回值的范围是0-255,超过就会循环从0开始) 例:如果main返回值是256,输出的结果就是0 

2).程序运行中调用exit函数结束运行,$? 中保存exit函数的参数 

3).程序异常退出 $? 中保存异常出错的错误号 

3、进程的退出方式

       自愿的退出:在main函数中return 0、调用exit()、调用_exit()、调用_Exit() 

       非自愿的退出:被信号杀死 

三、进程间的切换

1、进程间的状态切换图 如下

1).运行态和就绪态都是可以运行的进程,他们的区别在于是否有CPU 

2).阻塞态是不可以运行的进程,即使有CPU也不可以运行 

3).阻塞态向就绪态发生切换时,如果当前CPU空闲,就会向运行态切换;如果CPU不空闲,就会继续保持就绪态 

2、进程切换: 

(1)就绪-→运行: 当调度程序认为某个处于就绪状态的进程应当执行时,便使其成为当前运行的进程,该进程就会从就绪状态进入运行状态。

(2)运行-→就绪:当前运行进程因时间片用完或被更高优先级进程抢先时,当前运行进程就会由运行状态转入就绪状态,并被放入就绪队列中(放入的顺序与调度算法有关)

上述两个状态转换由进程调度来完成。

(3)运行-→阻塞:当前运行进程可能因等待事件或者执行Io请求而被阻塞,从而由运行状态转入阻塞状态,将进程由运行队列。然后,执行进程调度程序,让出处理器。

(4)阻塞-→就绪:处于阻塞状态的进程所等待的事件变为有效或等待超时后,该进程将被唤醒,从而由阻塞状态进入就绪状态,将在阻塞队列的第一个进程转入就绪队列(放入的顺序与调度算法有关)。

四、 进程的创建fork()函数

1、fork()、getpid()、getppid()函数: 

  1. #include <unistd.h> 
  2. pid_t   fork();//创建进程 
  3. pid_t   getpid();//获取进程id 
  4. pid_t   getppid();//获取父进程id 

fork()函数不需要参数,它的返回值有3种情况 

1).对于父进程来说,fork()函数的返回值是子进程的进程id 

2).对于子进程来说,fork()函数的返回值是0 

3).如果创建出错,fork()函数的返回值是-1,并且子进程不被创建 

2、fork()函数后新进程的状态:

 1).fork()函数会创建一个新的进程,并从内核中为该进程分配一个新的进程id,之后会为这个新进程分配进程空间,并将父进程的进程空间中的内容复制到子进程的进程空间中,包括了父进程的数据段和堆栈段,并且和父进程共享代码段,这个时候,系统中又多了一个进程,这个进程和父进程一样,两个进程都要接受系统的调度。 

2).子进程复制了父进程0-3G的用户空间内容,以及父进程的PCB,但是是不是每次fork一个子进程的时候都要将父进程0-3G的地址空间完全拷贝一份,然后在映射到物理内存呢? 

答案是:父子进程之间遵循读时共享,写时复制的原则。也就是当子进程修改父进程的数据内容的时候,内核才会给子进程分配进程空间,并复制父进程的内容 

3).为什么fork()函数返回两次? 

由于在复制的时候复制了父进程的堆栈段,所以两个进程都停留在了fork()函数中,等待返回,因此fork()函数返回两次,一次是在父进程中返回,另一次是在子进程中返回,并且两次的返回值都是不一样的 

4).fork后父子进程的异同: 

刚fork后:

父子进程的相同处:全局变量、堆、栈、 

父子进程的不同处:进程id、fork()函数的返回值、父进程id、进程运行时间 

3、进程创建练习 

1).创建一个子进程,并查看父子进程输出的不同内容 

程序运行结果: 

查看进程的信息和运行结果做对比: 

 

注意:由于父进程和子进程在系统中时平等低位的,所有不能对他们的执行顺序进行假设,谁先被执行取决于系统的调度 

2).如果父进程不对a进行修改,这个时候子进程就是共享a的数据,如果父进程中对a进行修改,子进程只能复制a的数据了(读时共享,写时复制的验证) 

程序运行结果: 

3).循环创建n个子进程 

程序运行结果:

4).分析下面的输出结果 

这是因为“hahaha”没有加\n,此时“父进程”就会接着“hahahah”,这个时候遇到\n了就刷新了行缓存;fork完后的子进程会复制“hahaha”,这个时候“子进程”就会继续接在“hahaha”后 

运用到的知识点:就是行缓存要么满1024个字节才刷新,要么遇到\n才刷新 

5.分析下面运行结果: 

本题考查的是运算符还要fork的返回值 

如果||运算符左边为1的话,||运算符右边就不用考虑了 

如果||运算符左边为0的话,||运算符右边需要考虑是0还是1,这样才能判断||完之后的最终结果是0还是1了 

如果&&运算符左边为0的话,&&运算符右边就不用考虑了 

如果&&运算符左边为1的话,&&运算符右边就要考虑是0还是1,这样才能最终判断&&完后的结果是0还是1 

刚好打印6次 

五、孤儿进程和僵尸进程

1、孤儿进程: 

        孤儿进程就是父进程先于子进程结束,而子进程成为了孤儿进程,但是孤儿进程只是一瞬间的状态,因为孤儿进程的父进程成为了init(编号为1的)进程 

 孤儿院,init进程产生的进程 

2、僵尸进程:(进程死了留着尸体没人回收) 

僵尸进程就是子进程已经死亡,父进程没有回收,子进程残留资源(PCB)存放在内核中,这个时候子进程就是僵尸进程 

第一行是父进程,第二行是子进程,此时子进程处于僵尸态 

 3、僵尸进程占用资源怎么样清理? 

注意:僵尸进程是不能被kill命令杀死的,因为kill命令是用来终止进程的,僵尸进程是已经终止的进程 需要kill僵尸进程的父进程,僵尸进程就变成了孤儿僵尸进程,init进程就会成为他新的父进程,init会把僵尸进程回收释放掉 也就是kill 4874 。

六、exec函数族

1、exec函数族的功能:

       在我们的进程里(程序),去执行另外一个可执行程序,当我们在执行到exec这部分时,会把我们原先的程序给替换掉,但在调用exec前后的进程id不会发生变化。 

2、execlp函数 

execlp参数1是要程序名,参数2是argv[0],参数3是argv[1]…参数n是NULL 

例如:在子进程中用execlp调用ls -l这个指令 

运行结果: 

 

3、execl函数 

execl参数1是要路径+程序名,参数2是argv[0],参数3是argv[1]…参数n是NULL 

例1.在子进程中用execl调用ls -l的指令 

运行结果: 

 

七、wait函数

1、进程回收: 

1).只能由父进程回收已死亡的子进程 

2).在进行进程回收时,父进程可以获取子进程的退出状态 

  • A.子进程正常退出(在主函数return、exit()、Exit()、_exit())获取子进程的返回值 

  • B.子进程异常退出(在Linux中进程的异常退出都是因为收到了某个信号)   获取导致子进程异常退出的信号编号 

3).父进程回收子进程的方式(wait()、waitpid()) 

4).释放进程的遗留信息 

2、wait函数 

1).wait函数用法:如果不关心子进程的死亡信息参数可以传NULL 

2).wait函数的功能: 

A.阻塞等待子进程死亡 

B.回收子进程的残留资源 

C.获取子进程的退出状态 

3).我们使用wait函数的传出参数status来保存进程的退出状态 ,我们借助宏函数来进一步判断进程终止的具体原因 。

  1. WIFEXITED(status)               //为真,进程正常结束 
  2. WEXITSTATUS(status)              //上面宏为真,返回子进程退出的值,比如return 123,返回值就是123;exit(10),返回值就是10 
  3. WIFSIGNALED(status)             //为真,进程异常终止 
  4. WTERMSIG(status)                  //上面宏为真,返回的是使子进程终止的信号的编号 

3、wait()练习 

1).获取子进程正常退出的返回值 

运行结果: 

 2).获取子进程被信号杀死的信号编号 

运行结果: 

 4.wait函数总结 

父进程调用wait函数去回收子进程 ,一次wait只能回收一个子进程,要是回收多个子进程的话我们需要多次调用wait :

1).子进程当前没有死亡            父进程阻塞等待 

2).子进程已经死亡                   父进程中wait立刻返回,返回值是成功回收掉的子进程的进程id 

3).父进程当前没有子进程         父进程出错返回 

4).父进程当前有多个已经死亡的子进程             只能回收掉一个,并且优先回收先死的 

八、waitpid函数

1、waitpid函数用法: 

2、waitpid练习 

1).用waitpid回收指定子进程的进程id 

2).运行结果: 

第一第二行说明了此时的wpid是同一个 

第三行就是回收的子进程的进程id 

 

九、进程相关实例

1、对并行和并发的理解 

并行和并发都具有处理多个任务的能力,他们的区别在于是否同时 

并行可以同时处理多个任务 

并发是轮流处理多个任务 

举个例子来说明:我饭吃到一半,这个时候电话来了,我先停下来去接了电话,接完后再继续吃饭,这就说明我支持并发 

我饭吃到一般,电话来了,我一边吃饭一边接电话,这就说明了我支持并行 

2、进程和线程的基本概念 

3、进程与线程的区别 

4、为什么有了进程还要有线程 

5、进程的状态转换 

6、外中断和异常有什么区别 

7、守护进程、僵尸进程和孤儿进程 

8、如何避免僵尸进程 

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/236270
推荐阅读
相关标签
  

闽ICP备14008679号