进程和线程的区别?
- 进程是资源管理的基本单位,因为进程的创建和撤销过程中,系统都要为之分配系统资源(内存空间,I/O 设备,)这也是进程切换开销大的原因。而线程是程序执行的基本单位,线程不拥有系统资源,线程是进程的一条执行流程,因为线程的创建只涉及到一个数据结构的分配。
- 进程的上下文切换比线程的上下文切换要慢的多
- 进程是拥有资源的一个单位,线程不拥有系统资源,但是可以访问隶属于进程的资源
那说说进程上下文切换和线程上下文切换的具体过程和区别?
进程的上下文切换分两步: 1-因为在进程切换的时候,内存中已经缓存的地址空间将做废,所以需要缓存新的地址空间,切换页表 2-切换内核栈和硬件上下文
线程共享进程的地址空间,所以只需要切换内核栈和硬件上下文,线程切换的时候,不涉及虚拟地址空间的转换。
为什么虚拟地址空间切换比较耗时?
进程有自己的虚拟地址空间,把虚拟地址空间转化为物理地址需要查找页表,页表查找是一个很漫长的过程,通常会使用 Cache 来缓存地址映射,这里的 Cache 就是 TLB,TLB 的本质就是一个 Cache,用来加速页表查找,由于每个进程都有自己的虚拟地址空间,每个进程有自己的页表,进程切换导致 TLB 失效,Cache 失效导致命中率降低,那么虚拟地址转换为物理地址就会把变慢,程序运行就会变慢。
协程与线程的区别?
- 线程是进程中间的一条执行流程,同一个进程里面的多个线程可以共享代码段,数据段,打开文件等资源,但是每个线程都有自己的独立的寄存器和栈。
- 编写的代码是存储在硬盘的静态资源,编译后变成二进制可执行的文件,执行这个文件,这个文件被加载到内存,运行的文件是进程。
- 线程和进程都是同步机制, 协程是异步机制。
- 线程是抢占式,协程是非抢占式,用户释放使用切换到其他的协程。同一时间只有一个协程拥有运行的权利,相当于单线程的能力。
- 一个线程可以有多个协程,一个进程也可以有多个协程。
- goroutine 不被操作系统内核管理,而是由程序控制,线程是被分隔的 CPU 资源。
- 线程是被分隔的 CPU 资源。Thread 是 goroutine 的资源,但是 goroutine 不直接使用 thread 而是使用与 Processer 关联的 Thread
- goroutinek 可以保留上一次执行的状态
- 进程是资源管理的基本单位,线程是程序执行的基本单位,线程不拥有系统资源,只是运行必须的数据结构。每个线程有自己的堆栈,程序计数器和自己的局部变量,但是与分隔的进程相比,线程可以共享内存,文件句柄,
进程调度
一个人(CPU)本来在做 A 项目,过了一会去做 B 项目了。
发生这种情况的原因:
- CPU 在做 A ,做着做着发现 A 里面有一个指令
sleep
,那么这个时候,CPU 开始去做 B 项目。 - CPU(人) 在做 A ,做着做着旷日持久,实在受不了了。项目经理介入了,说这个项目 A 先停停,B 项目也要做一下,要不然 B 项目该投诉了。
进程间通讯方式有哪些?
管道
管道:管道通信,在 Linux 中常有这样的场景,把一个进程的输出作为另外一个进程的输入去处理,比如
$ mkfifo pipe
$ ls -l pipe
$ echo "name" > pipe
可以通过 mkfifo 来创建一个命名管道,(本质上也就是创建了一个文件),然后管道,文件追加内容。但是这个时候无法写入内容,这是因为内核对管道的默认定义行为是阻塞的,因为只有另外一个进程从管道读取才能写入内容。
FIFO 是命名管道 PIPE 是匿名管道。
存在的问题是:
- 使用匿名管道通讯的两个进程仅仅限于父子间进程。
- 命名管道可以在本机上的任意两个进程间通信。
信号
信号可以在任意的时间发送给某一个进程,而不需要直到该进程的状态。
- SIGHUP:用户从终端注销,所有已经启动的进程都将收到该进程.SIGHUP
- SIGINT:程序终止信号,在程序运行的过程中,按 Ctrl+C 将产生该信号。
- SIGQUIT:程序退出信号。程序运⾏过程中,按 Ctrl+\键将产⽣该信号。
- SIGBUS 和 SIGSEGV:进程访问⾮法地址。
- SIGFPE:运算中出现致命错误,如除零操作、数据溢出等。
- SIGKILL:⽤户终⽌进程执⾏信号。shell 下执⾏ kill -9 发送该信号。
- SIGTERM:结束进程信号。shell 下执⾏ kill 进程 pid 发送该信号。
- SIGALRM:定时器信号。
- SIGCLD:⼦进程退出信号。如果其⽗进程没有忽略该信号也没有处理该信号,则⼦进程退出后将形成僵⼫进程。
信号量
信号量是一个计数器,可以用来控制多个进程对资源的访问,信号量是一种锁机制。主要应用的场景是:进程之间或者同一个进程的不同的线程之间的同步手段。
消息队列
消息队列是消息的链接表,包括 Posix 消息队列和 System V 消息队列。消息队列的实现是:有写权限的进程向队列写入数据,有读权限的进程可以读走队列中间的消息。消息的队列克服了信号承载的信息量少,管道只能承载无格式的字节流以及缓冲区大小收限等缺点。
接口标准(POSIX 和 System V) System V 时期的不同系统接口不一样,给移植带来了一定的麻烦,而 POSIX 将不同操作系统之间的上层 API 进行了统一,更换平台时便于移植应用程序。目前 Linux 中使用 POSIX 较多,但 System V 同样也存在。自 Linux kernel 2.6.6 ,开始支持 POSIX 的消息队列 API。
消息队列的使用场景:
异步处理(存储传输的数据):
注册的时候,用户上传的注册信息,先发送给消息队列,消息队列立即给用户返回信息上传成功。而真正的注册步骤是由消息队列把数据发送给服务进行注册。对于用户来说,用户得到反馈的时间主要依赖于写入消息队列的时间。而写入消息队列本身是很快的。
应用耦合: 一个图片上传系统需要调用人脸识别系统。第一调用可能失败,第二延迟高,因为需要先让上传系统处理完之后再去调用人脸识别系统,人脸识别系统处理完之后才能返回给客户端,即使用户不需要是立即知道结果。如果使用消息队列,那么这里一个图片上传系统是作为生产者,人脸识别系统是消费者,图片上传系统不需要知道人脸识别系统是否对这些消息进行处理,以及何时对这些消息进行处理。事实上,由于用户不需要立即知道人脸识别的结果,因此人脸识别系统可以按照不同的调度策略,按照闲时、忙时对队列中的照片进行处理。
限流削峰:
购物的秒杀活动,一般因为瞬时访问量太大,服务器承受不了,但是如果增加一个消费队列,让大量的请求存储到消息队列,然后让服务器以可以承受的速度去处理请求。好处是:请求都是先进入队列,而不是由业务系统直接处理,减小了业务处理系统的压力。对于请求的队列长度可以做限制,在秒杀的场景下,事实上,后面进入的用户请求是无法被处理的,那么请求可以直接抛弃,返回给用户活动已经结束,商品已经售完。
消息驱动系统: 一个人脸识别系统需要对这个用户的所有照片进行聚类,聚类完成之后对该用户重新生成用户的人脸索引(加快查询)这三个子系统由消息队列连接起来,前一个阶段的处理结果放入消息队列,然后后一个阶段从中取出消息继续处理。这个的好处是:避免了直接调用下一个系统导致当前系统失败。每个子系统在处理消息的时候可以灵活处理。(定时处理,立即处理,不同速度处理。)
共享内存
共享内存的本质是:映射一段能够被其他进程访问的内存。一个进程创建一段共享内存,但是多个进程都可以访问。共享内存是最快的进程间通信方式,常常与其他通信机制配合使用,如信号量,来实现进程间的同步和异步。
Socket
Socket 通信和其他通信机制不同的是,它用于不同机器间的进程通信。
比较
- 管道:速度慢,容量有限。
- 共享内存是最快的 IPC 方式。
- Socket 任何两个进程都可以通信(但是速度慢)
- 信号量,只能用来同步,不能传递复杂消息。
- 消息队列:容量收到系统限制
线程间的同步方式?
临界区:把多线程的串行化来访问公共资源。 缺点:但是只能用于同步同一个进程间的线程,不同用来同步多个进程间的线程。
互斥量:为协调共同对一个共享资源的单独访问而设计。互斥对象只有一个,并且只有拥有互斥对象的线程才具有访问资源的权限 互斥量不仅可以用于同一个进程的不同的线程,还可以用于不同进程的线程之间。
互斥量是可以跨越进程使用,所以创建的互斥量需要的资源更多,所以如果只是在进程内部使用,那么使用临界区可以减少资源占用量。
信号量: 用户资源是有限的,允许多个线程在同一个时刻访问同一资源,但是需要限制在同一时刻访问次资源的最大的线程数。互斥量是信号量的一种特殊情况。当信号量代表的的最大资源数=1,那么这个信号量就是互斥量。适用场景是:Socket 程序中线程的同步。
- 信号量机制必须有公共内存,不能⽤于分布式操作系统,这是它最⼤的弱点;
- 使用时对信号量的操作分散而且难以控制
- 核心操作 P-V 分散在各用户程序的代码中,不容易管理和控制。
事件: 用来通知线程有些事情已经发生,通知后续任务开始。 事件对象通过通知操作来进行线程同步。不同进程中的线程的同步。
临界区和互斥量的异同点?
临界区是一段不能同时被多个线程运行的代码,因为该代码访问共享资源。
进入临界区解决冲突的办法:
- 如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入
- 进入临界区的进程必须等待
- 如果进程不能进入自己的临界区,则应该让出 CPU ,避免忙等待。
互斥锁用来保护临界区的算法。 信号量和互斥量是互斥锁的常见实现。
什么是死锁?死锁产⽣的条件?
两个进程相互无限的等待下去。
死锁产生的四个条件:
- 互斥条件:一个资源一次只能被一个进程使用。
- 请求和保持条件:(因为请求被阻塞,但是对已经获得的资源保持不放)一个进程因请求而被阻塞的时,对已经获得的资源保持不放。
- 不剥夺条件:进程获得资源在未完全使用完之前不可以被强行剥夺。
- 循环等待条件:若干个进程形成头尾相接的环形等待。
讲⼀讲 IO 多路复⽤?
I/O 多路复用是指内核一旦发现进程指定的一个或者多个 IO 条件准备读取,它就通知该进程。 IO 多路复用场合:
- 客户端处理多个描述字(一般是交互式输入和网络套接字接口),必须使用 IO 多路复用。
- 如果一个 TCP 服务器既要处理监听套接字,又要处理已连接的套接字,一般也要用到 IO 复用。
- 一个服务器既要处理 TCP 又要处理 UDP ,一般要用到 IO 复用。
- 与多进程和多线程技术相比,IO 多路复用的最大优点是:系统开销小。系统不用创建进程/线程,也不用维护这些进程,线程,大大减小系统的开销。
中断的处理过程?
- 保存现场到寄存器。
- 打开中断,便于响应较高级别的中断请求。
- 中断处理
- 关中断,保证恢复现场的时候不被新的中断打断
- 恢复现场:从堆栈中按序取出程序数据,恢复中断前的状态。
中断和轮询有什么区别?
轮询:
CPU 对特定设备轮流询问。
中断:
通过特定事件提醒 CPU
TCP 三次握手机制?为什么要三次握手?
第一步: 客户端 TCP 向服务端的 TCP 发送 (待补充 S)