Linux你必须知道的小知识-13

99 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情


2.37 说说线程间通信的方式有哪些?

参考回答

线程间的通信方式包括临界区、互斥量、信号量、条件变量、读写锁

  1. 临界区:每个线程中访问临界资源的那段代码称为临界区(Critical Section)(临界资源是一次仅允许一个线程使用的共享资源)。每次只准许一个线程进入临界区,进入后不允许其他线程进入。不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它进行访问。
  2. 互斥量:采用互斥对象机制,只有拥有互斥对象的线程才可以访问。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。
  3. 信号量:计数器,允许多个线程同时访问同一个资源。
  4. 条件变量:通过条件变量通知操作的方式来保持多线程同步。
  5. 读写锁:读写锁与互斥量类似。但互斥量要么是锁住状态,要么就是不加锁状态。读写锁一次只允许一个线程写,但允许一次多个线程读,这样效率就比互斥锁要高。

2.38 说说线程同步方式有哪些?

参考回答

线程间的同步方式包括互斥锁、信号量、条件变量、读写锁

  1. 互斥锁:采用互斥对象机制,只有拥有互斥对象的线程才可以访问。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。
  2. 信号量:计数器,允许多个线程同时访问同一个资源。
  3. 条件变量:通过条件变量通知操作的方式来保持多线程同步。
  4. 读写锁:读写锁与互斥量类似。但互斥量要么是锁住状态,要么就是不加锁状态。读写锁一次只允许一个线程写,但允许一次多个线程读,这样效率就比互斥锁要高。

2.39 说说什么是死锁,产生的条件,如何解决?

参考回答

  1. 死锁: 是指多个进程在执行过程中,因争夺资源而造成了互相等待。此时系统产生了死锁。比如两只羊过独木桥,若两只羊互不相让,争着过桥,就产生死锁。

  2. 产生的条件:死锁发生有四个必要条件
    (1)互斥条件:进程对所分配到的资源不允许其他进程访问,若其他进程访问,只能等待,直到进程使用完成后释放该资源;

    (2)请求保持条件:进程获得一定资源后,又对其他资源发出请求,但该资源被其他进程占有,此时请求阻塞,而且该进程不会释放自己已经占有的资源;

    (3)不可剥夺条件:进程已获得的资源,只能自己释放,不可剥夺;

    (4)环路等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

  3. 如何解决

    (1)资源一次性分配,从而解决请求保持的问题

    (2)可剥夺资源:当进程新的资源未得到满足时,释放已有的资源;

    (3)资源有序分配:资源按序号递增,进程请求按递增请求,释放则相反。

答案解析

举个例子,比如:如果此时有两个线程T1和T2,它们分别占有R1和R2资源

此时,T1请求R2资源的同时,T2请求R1资源。

这个时候T2说:你把R1给我,我就给你R2

T1说:不行,你要先给我R2,我才能给你R1

那么就这样,死锁产生了。如下图:

image-20201221105446608

2.40 有了进程,为什么还要有线程?

参考回答

  1. 原因

    进程在早期的多任务操作系统中是基本的执行单元。每次进程切换,都要先保存进程资源然后再恢复,这称为上下文切换。但是进程频繁切换将引起额外开销,从而严重影响系统的性能。 为了减少进程切换的开销,人们把两个任务放到一个进程中,每个任务用一个更小粒度的执行单元来实现并发执行,这就是线程

  2. 线程与进程对比

    (1)进程间的信息难以共享。 由于除去只读代码段外,父子进程并未共享内存,因此必须采用一些进程间通信方式,在进程间进行信息交换。

    多个线程共享进程的内存,如代码段、数据段、扩展段,线程间进行信息交换十分方便。

    (2)调用 fork() 来创建进程的代价相对较高,即便利用写时复制技术,仍然需要复制诸如内存页表和文件描述符表之类的多种进程属性,这意味着 fork() 调用在时间上的开销依然不菲。

    但创建线程比创建进程通常要快 10 倍甚至更多。 线程间是共享虚拟地址空间的,无需采用写时复制来复制内存,也无需复制页表。