目录
一、简述线程间的通信方式
线程间的通信方式包括:临界区、互斥量、信号量、条件变量、读写锁。
1、临界区
每个线程中访问临界资源的那段代码称为临界区(Critical Section)(临界资源是一次仅允许一个线程使用的共享资源)。每次只准许一个线程进入临界区,进入后不允许其它线程进入。不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它进行访问。
2、互斥量
采用互斥对象机制,只有拥有互斥对象的线程才可以访问,因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。
3、信号量
计数器,允许多个线程同时访问同一个资源。
4、条件变量
通过条件变量通知操作的方式来保持多线程同步。
5、读写锁
读写锁与互斥量类似,但互斥量要么是锁住状态,要么是不加锁状态。读写锁一次只允许一个线程写,但允许一次多个线程读,这样效率就比互斥锁要高。
二、简述线程同步方式
线程间同步的方式包括:互斥锁、信号量、条件变量、读写锁。
三、简述死锁及其产生条件,解决办法
1、死锁
指多个进程在执行过程中,因争夺资源而造成了互相等待,此时系统产生了死锁。比如两只羊过独木桥,若两只羊互不相让,争着过桥,就产生死锁。
2、产生条件
死锁发生有四个必要条件。
①互斥条件:进程对所分配到的资源不允许其它进程访问,若其它进程访问,只能等待,知道进程使用完成后释放该资源。
②请求保持条件:进程获得一定资源后,又对其他资源发出请求,但该资源被其他进程占有,此时请求阻塞,而且该进程不会释放自己已经占有的资源。
③不可剥夺条件:进程已获得的资源,只能自己释放,不可剥夺。
④环路等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
3、如何解决
①资源一次性分配,从而解决请求保持的问题;
②可剥夺资源:当进程新的资源未得到满足时,释放已有的资源;
③资源有序分配:资源按序号递增,进程请求按递增请求,释放则相反。
4、举例
如果此时有两个线程T1和T2,它们分别占有R1和R2资源。此时,T1请求R2资源的同时,T2请求R1资源。这时,T2说:你把R1给我,我就给你R2。T1说:不行,你要先给我R2,我才能给你R1。那么这样,死锁就产生了,如下图:
四、有了进程,为何还需要线程
1、原因
进程在早期的多任务操作系统中是最基本的执行单元。每次进程切换,都要先保存进程资源然后再恢复,这称为上下文切换。但是进程频繁切换将引起额外开销,从而严重影响系统的性能。为了减少进程切换的开销,把两个任务放到一个进程中,每个任务用一个更小粒度的执行单元来实现并发执行,这就是线程。
2、线程和进程对比
①进程间的信息难以共享。由于除去只读代码段外,父子进程并未共享内存,因此必须采用一些进程间通信方式,在进程间进行信息交换。但多个线程共享进程的内存,如代码段、数据段、扩展段,线程间进行信息交换十分方便。
②调用fork()来创建进程的代价相对较高,即便利用写时复制技术,仍需要复制诸如内存页表和文件描述符表之类的多种进程属性。这意味着fork()调用在时间上的开销依然不菲。但创建线程比创建进程通常要快10倍甚至更多。线程间是共享虚拟地址空间的,无需采用写时复制来复制内存,也无需复制页表。
五、单核机器上写多线程程序,是否要考虑加锁
在单核机器上写多线程程序,仍然需要线程锁。
原因:因为线程锁通常用来实现线程的同步和通信。在单核机器上的多线程程序,仍然存在线程同步的问题,因为在抢占式操作系统中,通常为每个线程分配一个时间片,当某个线程时间片耗尽时,操作系统会将其挂起,然后运行另一个线程。如果这两个线程共享某些数据,不使用线程锁的前提下,可能会导致共享数据修改引起冲突。
六、简述多线程和多进程的区别
1、一个线程从属于一个进程,一个进程可以包含多个线程。
2、一个线程挂掉,对应的进程挂掉,多线程也挂掉;一个进程挂掉,不会影响其它进程,多进程稳定。
3、进程系统开销显著大于线程开销,线程需要的系统资源更少。
4、多个进程在执行时拥有各自独立的内存单元,多个线程共享进程的内存,如代码段、数据段、扩展段,但每个线程拥有自己的栈段和寄存器数组。
5、多进程切换时需要刷新TLB并获取新的地址空间,然后切换硬件上下文和内核栈,多线程切换时只需要切换硬件上下文和内核栈。
6、通信方式不一样。
7、多进程适用于多核、多机分布,多线程适用于多核。