一、简单说一下并发与并行
并行是指两个或者多个事件在同一时刻发生,而并发是指两个或者多个事件在同一时间间隔内发生;并行是在不同实体的多个事件,并发是在同一实体上的多个事件。
二、进程与线程的区别与联系
进程是资源分配的最小单位,而线程是CPU调度的最小单位
创建进程或者撤销进程,系统都要为之分配或回收资源,操作系统开销远大于创建或者撤销线程时的开销。
不同进程地址空间相互独立,同一进程内线程共享同一块地址空间,一个进程的线程在另一个进程内是不可见的。
进程间不会相互影响,而一个线程挂掉将可能导致整个进程挂掉。
三、为什么有了进程还要有线程?
进程可以使多个程序并发执行,以提高资源的利用率和系统的吞吐量,但是其带来了一些缺点:
进程在同一时间只能干一件事情;
进程在执行的过程中如果阻塞,整个进程就会被挂起,即使进程中有些工作不依赖和等待的资源,仍然不会执行。
基于进程的缺点,操作系统引入线程作为并发执行的基本单位,从而减少程序在并发执行时所付出的时间和空间的开销,提高并发性能。
四、进程间通信的方式有哪些
管道
它是半双工的,具有固定的读端和写端
它只能用于父子进程和兄弟进程之间的进程通信
它可以是看成是一种特殊的文件,对于它的读写也可以使用普通的read,write函数等,它不属于其他任何文件系统,并且只存在于内存中。
命名管道
FIFO可以在无关的进程之间交换数据,与无名管道不同;
FIFO有路径名与之相关联,它可以是一种特殊设备文件形式存在于文件系统中。
消息队列
它是消息的链接表,存放在内核中,一个消息队列由一个标识符ID来标识,消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
消息队列独立于发送于接收进程,进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按照消息的内存读取。
信号量
信号量是一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信的数据;
它用于进程间同步,若要在进程间传递数据需要结合共享内存。
信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作。
每次对信号量的PV操作对信号量值的加减正整数
支持信号量组
共享内存
指两个或者多个进程共享一个给定的存储区
共享内存是最快的一种IPC,因为进程是直接对内存进程存取。
五、什么是死锁
死锁指多个进程在运行的过程中因为争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用他们无法再向前推进。
1、产生死锁的原因
资源竞争
程序执行顺序不当
2、死锁产生的必要条件
互斥条件:进程要求对所分配的资源进行排他控制,即在一段时间内某资源仅为一进程所占有。
请求和保持条件:当进程因为请求资源而阻塞时,对已获得的资源保持不放
不可剥夺条件:进程已经获得的资源在未使用完之前,不能剥夺,只能在自己使用完时自己释放
环路等待条件:在不发生死锁时,必然存在一个进程。
3、怎么预防死锁
预防死锁的方法是使四个必要条件中的后三个条件之一不能成立,来避免发生死锁。
第一个必要条件,因为它是由设备的固有条件所决定的,不仅不能改变,还应加以保证
破坏请求条件:一次性分配所有的资源,这样子就不再有请求了
破坏保持条件:只要有一个资源得不到分配,也不给这个进程分配其他资源。
破坏不可争夺条件:当某个进程获得了部分资源,但得不到其他资源,则释放已经占有的资源
破坏环路等待条件:系统给每类资源赋予一个编号,每个进程按照编号递增的顺序请求资源,释放则相反。
4、怎么解除死锁
资源剥夺:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他死锁进程(注意防止被挂起的进程长时间得不到资源);
撤销进程:强制撤销部分、全部死锁并剥夺这些进程的资源;
进程回退:让一个或者多个进程回退到足以避免死锁的地步。进程回退时自愿释放资源而不是被剥夺,要求系统保持进程的历史信息,设置还原点。
六、介绍一下几种典型的锁
读写锁
多个读着可以同时进行读
写着必须互斥(只允许一个写者写,也不能读着写着同时进行)
写者优于读着
2、互斥锁
一次只能一个线程拥有互斥锁,其他线程只能等待
互斥锁是在抢锁失败的情况下主动放弃CPU进入睡眠直到锁的状态改变自动唤醒,而操作系统只负责线程的调度,为了实现锁的状态反生改变时唤醒阻塞的线程。需要把锁交给操作系统管理,所以互斥锁在加锁操作时涉及上下文的切换,互斥锁实际的效率还是可以让人接受,加锁时间大概100ns,而实际上互斥锁的一种可能的实现是先自旋一段时间,当时间超过了阈值后将线程投入睡眠,因此在发生并发运算中使用互斥锁的效果不亚于自旋锁。
3、条件变量
互斥锁一个明显缺点只有锁定和非锁定两种状态,而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁,他常和互斥锁一起使用,以免出现竞太条件,当条件不满足时,线程会解开相应的互斥锁并阻塞线程然后等待条件反生变化,一但其他的某个线程改变了条件变量,他将通知相应的条件变量唤醒一个或者多个正被次条件变量阻塞的线程。
3、自旋锁
如果进线程无法取得锁,进线程不会立刻放弃CPU的时间片,而是一直循环尝试获得锁,直到获取为止,如果别的线程长期占有锁,那么自旋就是浪费CPU做无用功,自旋锁一般应用于加锁时间很短的场景。