进程线程的区别,以及多进程多线程的使用场景
区别
进程是分配资源的基本单位,线程是系统调度的基本单位
进程上下文切换比线程的上下文切换开销大
进程有独立的地址空间,线程是共用一个进程内的地址空间
进程崩溃的话会有保护机制让其重启,线程崩溃将导致整个进程死掉
多进程使用场景:
Chrome浏览器就是多进程方式。
原因
1可能存在一些网页不符合规范,容易崩溃,采用多进程一个网页崩溃不会影响其他网页;而采用多线程会
2 网页之间互相隔离,保证安全,不必担心某个网页中的恶意代码会取得存放在其他网页中的敏感信息
多线程使用场景:
线程之间有数据共享的(不同任务间需要大量共享数据或则频繁通信时)
提供非均质的服务(有优先级处理)事件响应有优先级
单任务并行计算
当人与io交互的应用 良好的用户体验 (键盘鼠标的输入, 立即响应)
案例:
桌面软件,响应用户输入的是一个线程,后台程序处理是另外的线程
考虑:
需要频繁创建销毁的优先使用线程
需要进行大量计算的优先使用进程(CPU频繁切换,如图像处理,算法处理)
强相关用线程,弱相关的处理用进程(业务相关性不大就是弱相关)
用户态和内核态
如何从用户态进入内核态
系统调用
主动切换的方式,用户态通过系统调用申请使用操作系统提供的服务程序完成工作。例如fork就是执行了一个创建新进程的系统调用。
异常
如果当前进程运行在用户态,如果这个时候发送了异常事件,就会触发切换。例如:缺页异常
外设中断
当外设完成用户的请求时,会想cpu发送中断信号。这时cpu会暂停执行下一条即将要执行的指令而转到与中断信号对应的处理程序去执行,如果前面执行的指令是用户态下的程序,那么转换的过程就是由用户态向内核态的切换。如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后边的操作等
进程间通信的方式
1.管道
2.命令管道
3.信号
4.信号量
5.共享内存
6消息队列
7.内存映射
详细描述
得分点 管道、命名管道、信号、消息队列、共享内存、内存映射、信号量、Socket 标准答案 进程间通信主要包括:管道、命名管道、信号、消息队列、共享内存、内存映射、信号量、Socket:
- 管道 管道也叫无名(匿名)管道,它是是 UNIX 系统 IPC(进程间通信)的最古老形式,所有的 UNIX 系统都支持这种通信机制。管道本质其实是内核中维护的一块内存缓冲区,Linux 系统中通过 pipe() 函数创建管道,会生成两个文件描述符,分别对应管道的读端和写端。无名管道只能用于具有亲缘关系的进程间的通信。
- 命名管道 匿名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道(FIFO),也叫命名管道、FIFO文件。有名管道(FIFO)不同于匿名管道之处在于它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,并且其打开方式与打开一个普通文件是一样的,这样即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能交换数据。
- 信号 信号是 Linux 进程间通信的最古老的方式之一,是事件发生时对进程的通知机制,有时也称之为软件中断,它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式。信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断,转而处理某一个突发事件。
- 消息队列 消息队列就是一个消息的链表,可以把消息看作一个记录,具有特定的格式以及特定的优先级,对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程则可以从消息队列中读走消息,消息队列是随内核持续的。
- 共享内存 共享内存允许两个或者多个进程共享物理内存的同一块区域(通常被称为段)。由于一个共享内存段会称为一个进程用户空间的一部分,因此这种 IPC 机制无需内核介入。所有需要做的就是让一个进程将数据复制进共享内存中,并且这部分数据会对其他所有共享同一个段的进程可用。与管道等要求发送进程将数据从用户空间的缓冲区复制进内核内存和接收进程将数据从内核内存复制进用户空间的缓冲区的做法相比,这种 IPC 技术的速度更快。
- 内存映射 内存映射(Memory-mapped I/O)是将磁盘文件的数据映射到内存,用户通过修改内存就能修改磁盘文件。
- 信号量 信号量主要用来解决进程和线程间并发执行时的同步问题,进程同步是并发进程为了完成共同任务采用某个条件来协调它们的活动。对信号量的操作分为 P 操作和 V 操作,P 操作是将信号量的值减 1,V 操作是将信号量的值加 1。当信号量的值小于等于 0 之后,再进行 P 操作时,当前进程或线程会被阻塞,直到另一个进程或线程执行了 V 操作将信号量的值增加到大于 0 之时。
- Socket 套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。Socket 一般用于网络中不同主机上的进程之间的通信。
共享内存的实现方式
共享内存的优缺点
优点:
我们可以看到使用共享内存进行进程之间的通信是非常方便的,而且函数的接口也比较简单,数据的共享还可以使进程间的数据不用传输,而是直接访问了内存,加快了程序的效率
缺点:
共享内存没有提供同步机制,这使得我们在使用共享内存进行进程之间的通信时,往往需要借助其他手段来保证进程之间的同步工作。
操作系统的io模型(阻塞,非阻塞,io多路复用,信号驱动io,异步io)
1.阻塞io
描述
应用程序的进程发起IO调用,但是如果内核数据还没有准备好的话,那应用程序就一直在阻塞等待,一直等到内核数据准备好了,从内核拷贝到用户空间才放回成功提示,此次io操作,称之为阻塞io
图示
经典的应用:
阻塞socket java BIO
缺点:
如果内核数据一直没准备好,那用户进程将一直阻塞,浪费性能,可以使用非阻塞IO优化
2.非阻塞io
描述:
如果内核数据还没有准备好,可以先放回错误信息给用户进程,让它不需要等待,而是通过轮询的方式再来请求,这就是非阻塞IO,简称NIO,Non-Blocking IO
图示
缺点:
虽然大幅提升了性能,但是它依然存在性能模型,即频繁的轮询,导致频繁的系统调用,同样会消耗大量的CPU资源。可以考虑IO复用模型,去解决这个问题
3.IO多路复用模型
前言
既然NIO无效的轮询会导致CPU资源消耗,我们等到内核数据准备好了,主动通知 应用程序再去进行系统调用,那不就好了吗?在这之前,我们先来复习下,什么是we年描述符fd(file descriptor),它是计算机科学中的一个术语,形式上是一个非负整数。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。
思路
系统给我们提供一类函数(如我们耳濡目染的select,poll,epoll函数),他们可同时监控多个fd操作,任何一个返回内核数据就绪,应用进程再发起recvfrom系统调用,应用程序通过调用select函数,可以同时监控多个fd,在select函数监控的fd中,只要有任何一个数据状态准备就绪了,select函数就会返回可读状态,这时应用进车再发起recvfrom请求去读取数据
描述
非阻塞io(NIO)中,需要N(N>=1)次轮询系统调用,然而借助select的IO多路复用模型,只需要发起一次询问就够了,大大优化了性能。
但是呢,select有几个缺点:
监听的io最大连接数有限,在linux系统上一般为1024
select函数返回后,是通过遍历fdset,找到描述符fd。(仅知道有I/O事件发生,却不知道是那个流,所以遍历所有的流)
因为存在连接数限制,所以后来又提出了poll,与select相比,poll解决了连接数限制问题。但是呢,select 和 poll一样还是需要通过遍历文件描述符来获取已经就绪的socket。如果同时链接大量的客户端,在一时刻可能只有极少出于就绪状态,伴随着监视的描述符数量的增长,效率也会线性下降。因此经典的多路复用模型epoll诞生。
为了解决select/poll存在的问题,多路复用模型epoll诞生,他采用事件驱动来实现。
图示
epoll先通过 epoll_ctl()来注册一个fd(文件描述符);一旦基于某个fd就绪时,内核会采用回调机制,迅速激活这个fd,当进程调用epoll_wait() 是便得到通知。这里去掉了遍历文件描述符的坑爹操作,而是采用监听事件回调的机制。这就是epoll的亮点。
多路复用的三种函数的对比
epoll明显优化了io的执行效率 ,但是进程调用epoll_wait()时,仍然可能被阨。能不能酱紫:不用我老是去问你数据是否准备就绪,等我发出请求后,你数据准备好了通知我就信了,这就诞生了信号驱动io模型
信号驱动模型
描述
信号驱动io不在用主动询问的方式去确认数据是否就绪,而是向内核发送一个信号(sigaction的时候建立一个sigio的信号),然后应用用户进程可以去做别的事,不用阻塞。当内核数据准备好后,在通过sigio信号通知应用程序,数据准备好后的可读状态。应用用户进程收到信号之后,立即调用recvfrom,去读取数据
图示
信号驱动IO模型,在应用进程发出信号后,是立即放回的,不会阻塞进程。他已经有异步操作的感觉了。但是你细看上面的流程图,发现数据复制到应用缓存的时候,应用进程还是阻塞的。回过头来看下。不管是bio还是nio还是信号驱动,在数据从内核复制到应用缓存的时候,都是阻塞的。还有没有优化的方案呢?AIO(真正的异步IO)
异步IO
前言
前面讲的BIO,NIO和信号驱动,在数据从内核复制到应用缓存的时候,都是阻塞的,因此都不算是真正的异步。AIO是实现了IO全流程的非阻塞,就是应用进程发出系统调用后,是立即返回的,但是立即返回的不是处理结果,而是表示提交成功类似的意思。等内核数据准备好,将数据拷贝到用户进程缓冲区,发送信号通知用户进程io操作执行完毕
异步io的优化思路很简单,只需要向内核发送一次请求,就可以完成数据集状态询问和数据拷贝的所有操作,并且不用阻塞等待结果。日常开发中,有类似的业务场景:比如发起一笔批量转账,但是批量转账处比较耗时,这时候后端可以先告知前端转账提交成功,等到结果处理完后,在通知前端结果即可
一次普通io的过程什么时候用到了系统调用
我怎么知道(皮一下,慢慢更新了)
介绍下io多路复用 (即一个线程利用(select/poll/epoll)既可以hold住多个socket)
有更好的答案答疑下啊哈哈
select poll 和 epoll最大的差别是什么(第一阶段,等待数据报的到来,epoll不会阻塞)
有更好的答案答疑下啊哈哈 (应该不会问到吧,问到更多的是区别)
read在三者中是用户发起还是内核发起?(用户发起)
io密集型和CPU密集型如何分配线程优先级
select和epoll的区别
1.select,poll,epoll虽然都会返回就绪文件描述符数量,但是select和poll并不会明确指出是哪些文件描述符准备就绪,而epoll会。造成的区别就是,系统调用返回后,调用select和poll的程序需要遍历监听的整个文件描述符找到是谁处于就绪,而epoll则直接处理即可
2.select,poll采用轮询的方式来检查文件描述符是否出于就绪态,而epoll采用回调机制。造成的结果就是,随着fd的增多,select和poll的效率会线性减低,而epoll不会受到太大影响,除非活跃的socket很多。
3.select,poll都需要讲有关文件描述的数据结构拷贝进内核,最后再拷贝出来。而 epoll创建的有关文件描述符的数据结构本来就存在于内核态中,系统调用返回时利用mmap()文件映射内存加速与内存空间的消息传递,即epoll使用mmap减少复制开销
epoll使用场景?select具体性能消耗在哪
epoll需要拷贝文件描述符吗
不需要,select,poll都需要讲有关文件描述的数据结构拷贝进内核,最后再拷贝出来。而 epoll创建的有关文件描述符的数据结构本来就存在于内核态中,系统调用返回时利用mmap()文件映射内存加速与内存空间的消息传递,即epoll使用mmap减少复制开销
缺页中断?os会干什么linux怎么查看缺页中断
io模型了解吗?3讲下select/poll/epoll?各自优劣势,底层实现,使用场景
进程通信方式
管道 消息队列 信号 信号量 共享内存
协程
信号和信号量的区别
信号:是由用户,系统或则进程发送给目标进程的信息,以通知目标进程某个状态的改变或则系统异常
信号量:信号量是一个特殊的变量,它的本质是计数器,信号量里面记录了临界资源的数目,有多少数目,信号量的值就为多少 ,进程对其访问都是原子操作(pv操作,p占用资源,v释放资源。他的作用就是,协调进程对共享资源的访问,让一个临界区同一时间只有一个进程在访问它)
所以他们两者的区别就显而易见了,信号是通知进程产生了某个事件,信号量是用爱同步进程的(用来协调进程对共享资源的访问的)
内核态用户态什么是零拷贝
虚拟内存的好处
页表,实现机制
操作系统内存管理
操作系统如何实现定时器的,用什么数据结构
操作系统中有哪些锁,对应的乐观锁,悲观锁,怎么实现的
如何控制并发,加什么锁,读写锁还是互斥锁
程序从加载到运行的过程
为什么线程消耗比协程大,具体体现在那些方面
生产中哪些服务用的进程,线程,为什么要这么做,有什么好处
死锁的必要条件
资源互斥
不可剥夺
请求和保持
形成环
死锁的预防
1破坏资源互斥
1.资源转换技术:把独占资源变成共享资源
2.SPOOLing技术的引用
解决不允许任何进程直接占有打印机的问题
设计一个“守护进程/线程”负责 管理打印机 ,进程需要打印时,将请求发送给该daemon,由它完成打印任务
2破坏不可抢占
当一个进程申请的资源被其他资源占用时,可以通过操作系统抢占这一资源(两个进程优先级不同)
局限性只适用于状态易于保存和恢复的资源(内存,CUP)
3破坏请求和保持
4.破坏循环等待条件
线程共享的有什么 ,不共享的有什么
为什么要有虚拟内存
内存分页的目的试试
进程状态
209