导图社区 进程
这是一篇关于day3的思维导图,主要内容包括:守护进程,回收进程资源,孤儿进程和僵尸进程,exec族函数,结束进程,进程,Linux下的多任务机制。
编辑于2024-12-01 11:41:18这是一篇关于day5day6的思维导图,主要内容包括:消息队列:信息是带有类型的 可以过滤,IPC通信:共享内存 消息队列 信号灯集、ipcs命令 查看共享内存 消息队列 信号量、ipcs -s 查看信号量、ipcs -m 查看共享内存、ipcs -q 查看消息队列,共享内存,管道:在内核开辟的一块缓冲区,信号,进程间通信的方式。
这是一篇关于day4的思维导图,主要内容包括:设置线程属性,线程的同步,线程的互斥,线程。线程概念:为进一步减少处理器的空转时间,支持多处理器以及减少上下文切换开销,进程演化出线程,它是进程内独立的一条运行路线,是内核调度的最小单元。
这是一篇关于day3的思维导图,主要内容包括:守护进程,回收进程资源,孤儿进程和僵尸进程,exec族函数,结束进程,进程,Linux下的多任务机制。
社区模板帮助中心,点此进入>>
这是一篇关于day5day6的思维导图,主要内容包括:消息队列:信息是带有类型的 可以过滤,IPC通信:共享内存 消息队列 信号灯集、ipcs命令 查看共享内存 消息队列 信号量、ipcs -s 查看信号量、ipcs -m 查看共享内存、ipcs -q 查看消息队列,共享内存,管道:在内核开辟的一块缓冲区,信号,进程间通信的方式。
这是一篇关于day4的思维导图,主要内容包括:设置线程属性,线程的同步,线程的互斥,线程。线程概念:为进一步减少处理器的空转时间,支持多处理器以及减少上下文切换开销,进程演化出线程,它是进程内独立的一条运行路线,是内核调度的最小单元。
这是一篇关于day3的思维导图,主要内容包括:守护进程,回收进程资源,孤儿进程和僵尸进程,exec族函数,结束进程,进程,Linux下的多任务机制。
day3
Linux下的多任务机制
//linux系统的特点:多任务、多用户、良好的可移植性 (1)多任务处理 多任务处理是指用户在同一时间内可以运行多个任务,每个正在执行的一个应用程序被称为一个任务 (2)任务的执行 一次任务的执行,可以迸发激活多个进程,这些进程互相合作来完成这个终极目标 (3)多任务执行的本质 处理器在某一时刻只能执行一个任务,每个任务创建时会被分配时间片。任务执行(占用时间片),时间片递减,操作系统的时间片用完时调度执行其他的任务,频繁切换并且时间非常短,给用户的感觉像是多个任务在同时运行
并发执行和并行执行
并发执行:不是绝对意义上的同时运行 是通过时间片轮转机制实现,快速频繁切换,给用户的感觉多个程序在同时运行
并行执行:绝对意义上的同时运行 是通过多个CPU实现
进程
概念:1)进程是一个程序在一个数据集上执行一次的过程 //程序=数据结构+算法 //进程实体:代码段+数据+pcb //pcb是进程存在的唯一标识 //pcb:进程资源信息 进程控制信息CPU现场信息 进程标志信息 2)进程是一个独立的 可调度的 任务 3)进程是操作系统进行资源分配和调度的最小分配 4)进程和程序的区别(重点) //本质区别:进程是动态的 程序是静态的,进程是一个程序在一个数据集上执行一次的过程 程序是保存在磁盘上有序指令的集合(程序控制的最小单位:指令) 程序是永存的,而进程是暂时性的 随着创建而产生 调度而运行 销毁而消亡,进程具有并发性 程序没有,进程是操作系统进行资源分配和调度的最小单位 程序不是,进程和程序不是一一对应的 一个进程可以对应多个程序 一个程序也可以对应多个进程 5)进程特点 并发性:系统中多个进程可以同时并发执行,互不干扰 动态性:进程有完整生命周期,在生命周期内进程状态不断变化 交互性:进程执行过程中可能与其他进程进行直接或者间接通信 独立性:进程是计算机资源分配和调度的基本单位 各个进程的地址空间是相互独立的 6)进程分类 交互式进程:经常与用户交互的进程,需要等待用户输入(vi编辑器) 批处理进程:不必与用户进行交互(编译器编译工作) 守护进程:一直在后台运行的进行,和任何终端不联系,启动就执行,关闭即结束(windows系统中的服务)
进程相关命令
查看所有进程相关静态信息 ps aux
查看进程动态信息 top
列出进程关系树 pstree
杀死进程 kill 必杀 kill -9
获取进程标识符pid
头文件及函数原型 #include <sys/types.h> #include <unistd.h> pid_t getpid(void); //功能: 获取当前进程的PID pid_t getppid(void); //功能:parent 获取当前进程父进程的PID (2) 返回值 pid_t //类型是什么?? typedef int pid_t;
返回值: getpid:当前进程的pid getppid:当前进程的父进程的pid
进程说明
1、进程PID 进程创建的时候,系统会给其分配一个PID,进程结束以后,会回收这个PID,但是不会立刻再次分配使用。Linux内核通过唯一的进程标识符来标识每个进程。 //进程的PID是有限资源,进程结束以后需要将进程的PID及时回收,避免因为PID不够而创建不了新的进程 2、进程与终端 运行在终端上的进程,其父进程为:终端 kill -9 可以关闭当前终端 3、当前unbutn版本进程pid上限:32768 cat /proc/sys/kernel/pid_max
进程的三个基本状态:运行态、就绪态、阻塞态
进程状态的详细划分:
运行态
阻塞态
暂停态 ctrl+z//会将前台的进程放入到后台,处于暂停状态
僵尸态 僵尸进程 ,此时的状态就是僵死态
消亡态 最终状态
就绪态 //进程 申请处理器 而得不到满足时,其状态变为就绪态
进程基本状态

创建子进程
fork函数
(2)功能 用于创建一个子进程,当执行完fork 就会出现一个新进程(新进程称为子进程,原来的进程称为父进程) fork执行完 子进程会 几乎 复制父进程所有东西,并且子进程从fork后面语句开始执行。
功能: 用于创建一个子进程,当执行完fork 就会出现一个新进程(新进程称为子进程,原来的进程称为父进程) fork执行完 子进程会 几乎 复制父进程所有东西,并且子进程从fork后面语句开始执行。
如何区分父子进程
要区分出 Hello World是谁打印的 //需要通过fork函数的返回值来区分,当前进程是子进程还是父进程 pid_t ret = fork(); if(ret == -1) { //fork执行失败 } if(ret == 0)//说明当前进程是子进程 { //子进程要做的事情 } else if(ret > 0)//说明当前进程是父进程,并且ret的值是子进程的PID { //父进程要做的事情 } //父子进程都要做的事情
当父进程创建完子进程后 父子进程谁先执行要看操作系统采用什么调度算法 在上面示例程序中 父进程先执行 所以父进程先结束 此时子进程还没结束 此时的子进程叫做孤儿进程 会被init进程接管 init进程(pid == 1)变成它的父进程 并且子进程会放在后台执行 不受终端控制
如何让子进程先执行:让父进程睡一秒,CPU不会等待先执行子进程
子进程拷贝父进程

fork创建多进程
#include <stdio.h> int main() { int i; for(i = 0; i < 3; i++) { fork(); } /* fork(); fork(); fork(); */ printf("11111111111\n"); //打印几遍---8遍 } 
守护进程
Linux中的两类进程
1、前台进程 运行在终端上 终端关闭 进程也随之结束 2、后台进程 不运行在终端 在后台运行 不受终端控制
守护进程
守护进程,也就是通常所说的Daemon进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件,守护进程常常在系统启动时开始运行,在系统关闭时终止Linux系统有很多守护进程,大多数服务都是用守护进程实现的 守护进程能够突破这种限制,它从开始运行,直到整个系统关闭才会退出。 //如果想让某个进程不会因为用户或终端的变化而受到影响,就必须把这个进程变成一个守护进程。
查看守护进程
ps ajx //ps 命令 ajx 参数
umask命令
文件权限掩码的作用: 二进制位是1,掩盖权限,二进制位是0,不掩盖 0002 :000 000 010 创建一个文件 给权限是0666 110 110 110 文件权限掩码 0002 000 000 010 实际系统有的权限 111 111 101 你想要的 必须 系统得有 110 110 110 &111 111 101 110 110 100------0664 单独敲 umask 是查看文件权限掩码 敲 umask 0666 是将系统文件权限掩码改为 0666
功能:查看当前系统的文件权限掩码
单独敲 umask 是查看文件权限掩码 敲 umask 0666 是将系统文件权限掩码改为 0666
如何编写守护进程
(1)创建一个子进程,结束父进程(让其成为孤儿进程) (2)子进程创建新会话(setsid()函数) (3)修改进程当前目录(chdir("/tmp"))//不是必须的change directory (4)重置文件权限掩码(umask(0)) (5)关闭子进程从父进程复制过来的文件描述符
int num = getdtablesize(); //获取文件描述符表大小 int i; for(i = 0; i < num; i++) { close(i); }
exec族函数
(2)头文件及函数原型 #include <unistd.h> int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); //...表示多个参数 int execle(const char *path, const char *arg, ..., char * const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execvpe(const char *file, char *const argv[], char *const envp[]); l //list 缩写 希望接收以逗号分隔的参数列表,列表以NULL作为结尾标志 p //PATH 系统会按照PATH环境变量进行路径进行查找命令 e //enviroment 缩写 指定当前进程所使用的环境变量 v //vertor 缩写 参数传递为以NULL结尾的字符指针数组 六个函数返回:若出错则为- 1,若成功则不返回 int execlp(const char *file, const char *arg, ...); //...表示多个参数 const char *file //执行的新程序的名称(可以有路径修饰) const char *arg, ... // 可执行程序在命令行的执行的过程 (是否需要命令行传递参数) ls //命令,同时ls也是一个可执行的程序 cp //命令,同时cp也是一个可执行的程序
什么时候我们想到用exec族函数 当想要在当前的程序中去调用另外一个程序的时候,使用exec族函数 execute //执行
功能: 用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。 当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其main函数开始执行。 因为调用exec并不创建新进程,所以前后的进程PID并未改变。exec只是用另一个新程序替换了 当前进程的正文、数据、堆和栈段
回收进程资源
如何回收进程资源
父进程应该晚于子进程结束,父进程调用wait族函数,来回收子进程的资源 wait函数:阻塞等待子进程结束 一旦子进程结束 立刻回收资源并接解除阻塞 waitpid函数:等待某一个子进程结束,一旦那个子进程结束 立刻回收资源 可以阻塞也可以非阻塞
wait函数
(2)头文件及函数原型 #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); //调用参考 wait(NULL); int s;//s里面是随机数 //当想要获取子进程结束时的状态的时候,需要通过参数上地址传递的方式,来获取 wait(&s);//调用函数之后,s里面不是随机数了,保存的是子进程结束时的状态 (3)函数参数 status是一个整型指针,指向的对象用来保存子进程退出时的状态。 status若为空,表示忽略子进程退出时的状态,通常赋值为NULL status若不为空,表示保存子进程退出时的状态
功能:wait(当父进程执行此函数时,父进程 阻塞 等待子进程结束) 父进程执行到wait函数就会阻塞,等待子进程的结束,一旦有一个子进程结束,wait将结束阻塞 当子进程结束时,父进程会通过wait函数回收子进程的资源
返回值: 成功:pid_t //返回值是结束的那个子进程的PID 失败:-1
waitpid函数
(2) 头文件及函数原型: #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); //等待指定的子进程结束 waitpid(1122, NULL, 0); //第三个参数 是0,阻塞等待PID是1122这个子进程的结束,回收资源 waitpid(1133, NULL, WNOHANG); //第三个参数 WNOHANG 非阻塞回收PID是1133这个进程资源 //第三个参数是 WNOHANG, 如果子进程没有结束,waitpid函数的返回值一直是0 //当子进程结束的时候,waitpid函数的返回值就是结束的那个子进程的PID (3)参数说明: pid_t pid //pid > 0 回收进程的ID //pid = -1 回收任何一个子进程 此时作用和wait一样 //pid = 0 回收其组ID等于调用进程的组ID的任一子进程 //pid < -1 回收其组ID等于pid的绝对值的任一子进程 int *status //同wait函数的参数 int options: WNOHANG 表示不阻塞,waitpid不阻塞而立即返回,此时值为0,结束后返回值为结束子进程pid 0 阻塞
功能:指定等待某个子进程的结束
返回值: >0: 已经结束运行的子进程进程号 0: 使用WNOHANG且没有子进程退出 -1: 出错
孤儿进程和僵尸进程
孤儿进程 子进程未结束,父进程先结束,此时的子进程会被init进程接管,且放在后台运行,此时的子进程称为孤儿进程
僵尸进程 子进程先结束 父进程未结束 父进程没有调用wait族函数及时回收子进程的资源 此时子进程就是僵尸进程 和野指针一样 僵尸进程是绝对的坏事 必须避免僵尸进程的产生 因为僵尸进程占用有限资源PID
结束进程
1、exit函数
头文件与函数原型 #include <stdlib.h> void exit(int status); (3)参数: int status是一个整型的参数,可以利用这个参数传递进程结束时的状态。一般来说,0表示正常结束, 其它值表示出现了错误,当程序执行到exit函数时,就结束进程,但在结束进程前会刷新缓存区 exit(0); //0 正常结束 执行exit()函数后,会刷新缓存区,将缓存区中的内容写入到文件中,再结束进程 exit(-1); //-1 异常结束 执行exit()函数后,会刷新缓存区,将缓存区中的内容写入到文件中,再结束进程
功能:用于结束进程,当程序执行到exit函数时, 进程立刻结束,但在结束进程之前会刷新缓存区
正常结束:exit(0)
异常结束:exit(-1)
2、_exit函数
文件与函数原型 #include <stdlib.h> void _exit(int status); (3)参数 int status是一个整型的参数,可以利用这个参数传递进程结束时的状态。一般来说,0表示正常结束, 其它值表示出现了错误,当程序执行到exit函数时,就结束进程 _exit(0); //0 正常结束 执行_exit()函数后,不会刷新缓存区,直接结束进程 _exit(-1); //-1 异常结束 执行_exit()函数后,不会刷新缓存区,直接结束进程
功能:用于结束进程,当程序执行到_exit函数时, 进程立刻结束,不会刷新缓存区
正常结束:_exit(0)
异常结束:_exit(-1)
exit和_exit的区别 两个都可以立刻结束进程,并且参数都可以传递进程结束时的状态,但exit会在结束进程前刷新缓存区,_exit不会刷新缓存区