赞
踩
目录
1、ps -ajx:显示正在运行的相关联进程信息(父进程PPID)
3、可以通过管道过滤出你想查看的信息 ps -ajx | grep 要过滤的信息
2、我们可以通过指令:echo $? 来得到已经结束进程的结束状态 。
1、fork()、getpid()、getppid()函数:
查看正在运行进程的信息,只不过是更加详细,如有PID(进程id)、PPID(父进程id)、PGID(进程组id)、SID(会话id) 如下图所示:
查看正在运行进程的信息(主要是进程的PID),R运行、S睡眠、I空闲、Z僵尸 如下图所示:
如:ps -ajx | grep ./main ,如下图所示:
正常退出(自愿的):程序里面正常退出,如return 0
错误退出(自愿的):发生错误被我们检查到就自己退出了,如打开一个不存在的文件,会给我们返回一个错误编号,这个时候进程的退出就是错误退出
严重错误(非自愿的):段错误
被其他进程杀死(非自愿的):使用kill杀死进程
$? 是Linux shell 中的一个内置变量其中保存的是最近一次运行的进程的返回值,这个返回值有以下3种情况:
1).程序中的main函数运行结束,$? 中保存的是main函数的返回值(注意这个返回值的范围是0-255,超过就会循环从0开始) 例:如果main返回值是256,输出的结果就是0
2).程序运行中调用exit函数结束运行,$? 中保存exit函数的参数
3).程序异常退出 $? 中保存异常出错的错误号
自愿的退出:在main函数中return 0、调用exit()、调用_exit()、调用_Exit()
非自愿的退出:被信号杀死
1).运行态和就绪态都是可以运行的进程,他们的区别在于是否有CPU
2).阻塞态是不可以运行的进程,即使有CPU也不可以运行
3).阻塞态向就绪态发生切换时,如果当前CPU空闲,就会向运行态切换;如果CPU不空闲,就会继续保持就绪态
(1)就绪-→运行: 当调度程序认为某个处于就绪状态的进程应当执行时,便使其成为当前运行的进程,该进程就会从就绪状态进入运行状态。
(2)运行-→就绪:当前运行进程因时间片用完或被更高优先级进程抢先时,当前运行进程就会由运行状态转入就绪状态,并被放入就绪队列中(放入的顺序与调度算法有关)
上述两个状态转换由进程调度来完成。
(3)运行-→阻塞:当前运行进程可能因等待事件或者执行Io请求而被阻塞,从而由运行状态转入阻塞状态,将进程由运行队列。然后,执行进程调度程序,让出处理器。
(4)阻塞-→就绪:处于阻塞状态的进程所等待的事件变为有效或等待超时后,该进程将被唤醒,从而由阻塞状态进入就绪状态,将在阻塞队列的第一个进程转入就绪队列(放入的顺序与调度算法有关)。
- #include <unistd.h>
-
- pid_t fork();//创建进程
-
- pid_t getpid();//获取进程id
-
- pid_t getppid();//获取父进程id
fork()函数不需要参数,它的返回值有3种情况
1).对于父进程来说,fork()函数的返回值是子进程的进程id
2).对于子进程来说,fork()函数的返回值是0
3).如果创建出错,fork()函数的返回值是-1,并且子进程不被创建
1).fork()函数会创建一个新的进程,并从内核中为该进程分配一个新的进程id,之后会为这个新进程分配进程空间,并将父进程的进程空间中的内容复制到子进程的进程空间中,包括了父进程的数据段和堆栈段,并且和父进程共享代码段,这个时候,系统中又多了一个进程,这个进程和父进程一样,两个进程都要接受系统的调度。
2).子进程复制了父进程0-3G的用户空间内容,以及父进程的PCB,但是是不是每次fork一个子进程的时候都要将父进程0-3G的地址空间完全拷贝一份,然后在映射到物理内存呢?
答案是:父子进程之间遵循读时共享,写时复制的原则。也就是当子进程修改父进程的数据内容的时候,内核才会给子进程分配进程空间,并复制父进程的内容
3).为什么fork()函数返回两次?
由于在复制的时候复制了父进程的堆栈段,所以两个进程都停留在了fork()函数中,等待返回,因此fork()函数返回两次,一次是在父进程中返回,另一次是在子进程中返回,并且两次的返回值都是不一样的
4).fork后父子进程的异同:
刚fork后:
父子进程的相同处:全局变量、堆、栈、
父子进程的不同处:进程id、fork()函数的返回值、父进程id、进程运行时间
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次
孤儿进程就是父进程先于子进程结束,而子进程成为了孤儿进程,但是孤儿进程只是一瞬间的状态,因为孤儿进程的父进程成为了init(编号为1的)进程
孤儿院,init进程产生的进程
僵尸进程就是子进程已经死亡,父进程没有回收,子进程残留资源(PCB)存放在内核中,这个时候子进程就是僵尸进程
第一行是父进程,第二行是子进程,此时子进程处于僵尸态
注意:僵尸进程是不能被kill命令杀死的,因为kill命令是用来终止进程的,僵尸进程是已经终止的进程 需要kill僵尸进程的父进程,僵尸进程就变成了孤儿僵尸进程,init进程就会成为他新的父进程,init会把僵尸进程回收释放掉 也就是kill 4874 。
在我们的进程里(程序),去执行另外一个可执行程序,当我们在执行到exec这部分时,会把我们原先的程序给替换掉,但在调用exec前后的进程id不会发生变化。
execlp参数1是要程序名,参数2是argv[0],参数3是argv[1]…参数n是NULL
例如:在子进程中用execlp调用ls -l这个指令
运行结果:
execl参数1是要路径+程序名,参数2是argv[0],参数3是argv[1]…参数n是NULL
例1.在子进程中用execl调用ls -l的指令
运行结果:
1).只能由父进程回收已死亡的子进程
2).在进行进程回收时,父进程可以获取子进程的退出状态
A.子进程正常退出(在主函数return、exit()、Exit()、_exit())获取子进程的返回值
B.子进程异常退出(在Linux中进程的异常退出都是因为收到了某个信号) 获取导致子进程异常退出的信号编号
3).父进程回收子进程的方式(wait()、waitpid())
4).释放进程的遗留信息
1).wait函数用法:如果不关心子进程的死亡信息参数可以传NULL
2).wait函数的功能:
A.阻塞等待子进程死亡
B.回收子进程的残留资源
C.获取子进程的退出状态
3).我们使用wait函数的传出参数status来保存进程的退出状态 ,我们借助宏函数来进一步判断进程终止的具体原因 。
- WIFEXITED(status) //为真,进程正常结束
-
- WEXITSTATUS(status) //上面宏为真,返回子进程退出的值,比如return 123,返回值就是123;exit(10),返回值就是10
-
- WIFSIGNALED(status) //为真,进程异常终止
-
- WTERMSIG(status) //上面宏为真,返回的是使子进程终止的信号的编号
1).获取子进程正常退出的返回值
运行结果:
2).获取子进程被信号杀死的信号编号
运行结果:
父进程调用wait函数去回收子进程 ,一次wait只能回收一个子进程,要是回收多个子进程的话我们需要多次调用wait :
1).子进程当前没有死亡 父进程阻塞等待
2).子进程已经死亡 父进程中wait立刻返回,返回值是成功回收掉的子进程的进程id
3).父进程当前没有子进程 父进程出错返回
4).父进程当前有多个已经死亡的子进程 只能回收掉一个,并且优先回收先死的
1).用waitpid回收指定子进程的进程id
2).运行结果:
第一第二行说明了此时的wpid是同一个
第三行就是回收的子进程的进程id
并行和并发都具有处理多个任务的能力,他们的区别在于是否同时
并行可以同时处理多个任务
并发是轮流处理多个任务
举个例子来说明:我饭吃到一半,这个时候电话来了,我先停下来去接了电话,接完后再继续吃饭,这就说明我支持并发
我饭吃到一般,电话来了,我一边吃饭一边接电话,这就说明了我支持并行
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。