文章目录
Linux 进程 ---- 看的视频是华清远见的曾老师的视频。看的书籍是Linux 编程技术详解。
多进程 多线程,是多任务程序的一种机制。
多任务:比如QQ可以同时和多人聊天,下载和上传。
第一讲:
进程的概念
程序: 可执行程序,存放在磁盘上的指令和数据的有效的集合(文件)
静态的
进程:执行一个程序所分配的资源的总称。
进程是程序的一次执行过程
动态的,包括创建,调度,执行和消亡。
进程包含的内容
进程–>正文段–用户数据段–系统数据段—》程序
系统数据段—>进程控制块–>cpu寄存器的值–>堆栈。
进程控制块:(pcb: Process control block)
进程表示 PID: (一个正整数)
进程用户:
进程状态,优先级
文件描述符表:存档进程打开的所有文件的信息,
寄存器的作用:
pc: program counter(程序计数器)(下一条指令的地址)
进程:在宏观上是并发的。在微观上是顺序执行的。
堆栈:
栈(所有的局部变量都在栈上被创建,(函数的参数,返回值)也都在栈上被自动释放)
进程的类型:
交互进程:在shell下启动,在前台运行,也可以在后台运行。(默认在前台运行)
(前台进程可以往终端输入也可以往终端输出)
(后台进程无法从终端读取输入,但是可以往终端输出)
批处理进程:和在终端无关,被提交到一个作业队列中,以便顺序执行。
(一般是和终端无关,由系统管理员用到,开发很少用到)
守护进程:和终端无关,一直在后台运行
(服务器大都以守护进程的形式存在。)
进程的状态
运行态:(正在运行,可运行(准备运行))
等待态:(进程在等待一件事情的发生或者某种系统资源)
可中断:
不可中断:
停止态:
进程被终中止,收到信号后可以继续运行
死亡态:已经终止进程,但是pcb没有被释放。
第二讲
查看进程信息(熟练)
ps
查看系统进程快照 ( Process Status)
ps -ef:显示所有的进程信息:
这个是我在我的电脑上截取的:
UID:进程所有者,创建进程用户的id
pid: 每个进程的进程号 ppid:每个进程的副进程号
stime:进程的开始时间 TTY:进程所关联的终端
TIME:进程执行时占用的时间
CMD:进程所对应的程序的名称
ps-ef|more
ps-ef|grep test
在Linux 虚拟机中创建一个简单的程序,让他空跑。在另一侧我们采用 ps -ef |grep test 直接打印出我们需要的信息。(我们可以看到他的资源占用率时99% ,整个资源基本都被占用了)
ps aux
可以显示进程当前的状态。
在原来的函数上,新加入 getchar();这个函数会一直等待输入,直到有信息输入回车时,才会进入运行状态,具体的状态的描述:如下 man ps
top 查看进程动态信息(每隔0.3s就会重新刷新一次信息)
/proc 查看进程详细信息
改变进程优先级(熟练)
nice
按用户指定的优先级进行运行
nice值是: -20 ---- 19 (-20 优先级最高!!默认值是0)
通过TOP命令查看:
通过nice来更改优先级的值。
renice
renice 改变正在运行进程的优先级(改变已经有的优先级)
强调一点:普通的用户只能降低优先级。(管理员可以提高和降低优先级)
前后台进程切换(熟练)
jobs 查看后台进程
(后台进程,也称为后台作业)
新建两个后台任务:
通过jobs来查看后台的进程
fg 把后台运行的进程放到前台运行
用于将后台作业(在后台运行的或者在后台挂起的作业)放到前台终端运行
Foreground
通过fg命令:把后台的任务,变成前台的任务。
bg 将挂起的进程在后台运行
第三讲:
创建子进程
创建进程 --fork
#include <unsigned.h>
pid_t fork(void)
创建新的进程,失败时返回-1;
成功时: 父进程 返回 子进程的进程号, 子进程返回0 ( 为了区分父子进程,通过fork返回值进行区分 )
父子进程
子进程继承了父进程的内容,(子进程几乎继承了父进程所有的东西)(但是他们的pid ppid 不同)
父子进程有独立的地址空间,互不影响。(他们对应的物理内存时不一样的,有自己独立的代码和数据)【Linux 用来提高效率也采用了一些其他的技术】
若父进程先结束
子进程成为孤儿进程,被init进程来收养。
一个进程在他的生命周期内,进程号不会变化,但是父进程号会发生变化
若子进程先结束:
父进程没有及时的回收,子进程就会变成僵尸进程。
当进程结束的时候,进程的相关资源都已经被释放了。但是进程的PCB 没有被回收,(pcb存放的进程的返回值,以及结束方式)系统规定 必须由父进程来进行回收。
父进程一定是从main()函数开始执行,
那么子进程是从什么地方开始执行?
子进程从 fork ()的下一条指令开始执行。
父子进程谁先执行?
通常是父进程先执行,但是不确定,要看系统先调度谁!
父进程能够多次调用fork?子进程呢?
父进程可以多次调用fork,创建子进程,需要去回收
子进程也可以创建新的子进程,叫做孙子进程。
结束进程
exit
_exit
他们的参数一样,
void exit (int status);
void _exit (int status);
结束当前的进程并将status返回,
exit结束进程时会刷新(流),缓冲区
第四讲:
如何在进程中去执行另外一个函数。
进程-- exec函数族
进程调用exec函数族执行某个程序,
进程当前的内容被指定的程序替换
实现父子进程执行不同的程序
父进程创建子进程
子进程调用exec函数族
父进程不受影响
shell基本的工作原理相当于父进程,shell创建的子进程里面调用exec进行运行指定的程序。
execl
execlp
execl
execlp
#include <unistd.h>
int execl (const char *path ,const char *arg,......)
//执行指定的Path所对应的内容
//成功没有返回值,执行指定的程序
//失败返回-1(如没有创建,没有权限)
// path 执行的程序的名称,包含路径
//arg ...传递给执行的程序的参数列表
int execlp(const char *file ,const char *arg,......)
file 执行的程序的名称,在path中查找 。
在程序中执行ls命令,显示/etc目录下所有的文件的详细信息
if(execl("/bin/ls","ls","-a","-l","/etc",NULL)<0){
perror("execl");
}
if(execlp("ls","ls","-a","-l","/etc",NULL)<0){
perror("execl");
}
//只有第一个参数不同,execl 需要进行路径的指定,execlp在path中寻找,因此不用指定路径,只需要指明函数名称。
execv
execvp
#include <unistd.h>
int execv (const char *path ,const char *argv[],......)
//V 代表是一个数组。
//把要传的参数都放在数组里,
//成功时,运行指定的程序;失败时返回EOF
argv[] 封装成指针数组的形式
执行ls命令,显示etc目录下的所有的文件的详细信息
char *arg[]={"ls","-a","-l","/etc",NULL};
if(execv("/bin/ls",arg)<0)
{
perror("execv");
}
//第二种形式时:不需要路径。
if(execvp("ls",arg)<0)
{
perror("execv");
}
进程–system
#include <unistd.h>
int system (const char *command )
最简单的时使用system进行执行一个新的程序。
第五讲
wait
//进程回收
//子进程结束时由父进程进行回收
//孤儿进程由init 进程回收
//若没有及时回收会出现僵尸进程。
#include <unistd.h>
pid_t wait(int *status)
//整形的指针参数
//返回值是 pid_t的类型,相当于一个整形
成功回收一个子进程时,回收子进程的进程号:失败时返回EOF
若子进程没有结束,父进程会一直阻塞
若有多个子进程,哪个先结束就先回收哪一个子进程。返回结束的子进程的进程号。
status 指定保存子进程返回值和结束方式的地址。
(定义一个整形变量,把整形变量的地址传进去。而不是直接定义一个整形的指针,因为定义好之后,是一个随机数
相当于一个野指针)
status 为NULL表示直接释放子进程PCB ,不接收返回值。
int status;
pid_t pid;
if((pid=fork())<0){
perror("fork");
exit(-1);
}
else if(pid==0){
sleep(1);exit(2);
}
else {
wait(&status);
printf("%x\n",status);
}
返回值和结束方式
子进程exit /_exit /return 返回某个值(0-255)
父进程调用wait(&status)回收
WIFEXITED(status) //判断子进程是不时正常的结束。
WEXITSTATUS (status) //获取子进程的返回值
WIFSIGNENALED(status) //判断子进程是否被信号结束
WTERMSIG(status) //获取结束子进程的信号类型
waitpid
#include <unistd.h>
pid_t waitpid (pid_t pid ,int *status,int option);
成功时返回回收子进程的pid或者0;失败时返回 EOF
pid可用于指定回收哪个子进程或者任意子进程。
status 指定用于保存子进程返回值和结束方式的地址
option 指定回收方式,0或者WNOHANG //非阻塞
waitpid(pid,&status,0); //指定回收某一个子进程,pid进程号 阻塞的方式,子进程没有结束,
//父进程就一直阻塞
waitpid(pid,&status,WNOHANG );//非阻塞的方式。如果子进程结束了返回子进程的进程号
//如果子进程没有结束,父进程也会立刻返回,但是返回值时0.
waitpid(-1,&status,0); //回收当前进程的任意一个子进程。相当于wait
waitpid(pid,&status,WNOHANG ); //非阻塞 回收当前进程的任意一个子进程。