全网最精简进程与线程通信方式

引言

针对面试常考点,本文对进程线程通信方式进行简单总结,同时额外补充锁相关知识

目录

  • 进程

    • 管道
      • 无名管道
      • 有名管道
    • 系统IPC
      • 消息队列
      • 共享内存
      • 信号量
    • 套接字
  • 线程

    • 互斥锁
    • 信号量
    • 条件变量
    • 读写锁
    • 自旋锁
  • 补充

    • 死锁
    • 活锁
    • 公平锁
    • 非公平锁
    • 乐观锁
    • 悲观锁

一、 进程

提要:
进程的创建方式有两种:一种由操作系统创建(系统进程),一种由父进程创建(fork()函数),对于第二种创建方式,子进程完全复制了父进程的地址空间的内容,包括数据段和堆栈段的内容,但子进程却和父进程仅仅只共享代码段,不共享数据段和堆栈段,对于其他变量需要进行进程通信才可以实现交互,所以进程间的通信更关注的是两个进程间进行数据交互

1. 管道

操作系统在内核中开辟一块缓冲区进行管道通信(两个进程同一时刻进行单向通信)

实现原理:父子进程各自拥有一个文件描述符表,但是两者的内容是一样的,既然内容一样,那么指向的就是同一个管道,即父子进程看到了同一份公共资源

注:如果要双向通信,需建立两个管道
管道通信原理图
无名管道是不可见的文件,所以只允许有亲缘关系的进程进行通信
有名管道可以通过同一个路径名而看到同一份资源,所以允许无亲缘关系进程间的通信

特点:

  1. 管道通信依赖于文件系统,即管道的生命周期随进程
  2. 管道的通信被称为面向字节流,与通信格式没有关系
  3. 管道自带同步机制,保证读写顺序一致
  4. 缓冲区大小受到较大的限制

2. 系统IPC——消息队列

消息队列是一个双向通信的方式,其可以克服管道通信传递信息少、只能承载无格式字节流以及缓冲区大小受限等缺点
实现原理:内核地址空间中的内部链表,消息可以顺序地发送到队列中,并以不同方式从队列中获取

3. 系统IPC——共享内存

不同进程通过访问同一个逻辑内存,实现通信

注:

  1. 共享内存并未提供同步机制,所以可能会发生出错,需要加入信号量机制
  2. 因为共享内存通信方式是直接在内存上操作,所以速度最快
    共享内存原理图

4. 系统IPC——信号量

信号量通过计数器机制,可以实现防止多个进程同时访问一块资源
注:信号量的生命周期并不随进程的结束而结束,而是随内核的

5. 套接字

socket套接字可以实现多机通信

二、线程

所有线程都可以共享进程的资源,如代码段、数据段,但是每个线程都有自己独立的资源,如栈、寄存器,所以线程通信更关注的是互斥与同步

1. 互斥锁

确保同一时间只有一个线程能访问被互斥锁保护的资源,互斥锁只有上锁和解锁两种状态
互斥锁一般被设置成全局变量,锁定互斥量的线程与解锁互斥量的线程必须是同一个线程

2. 信号量

机制同进程通信中的信号量

3. 条件变量

条件变量是用来等待而不是用来上锁的,其通常允许线程挂起,直到共享数据上的某些条件得到满足,避免忙等待带来的不必要消耗

通常条件变量和互斥锁同时使用,以避免出现条件竞争,原因如下:
条件变量这个变量其实本身不包含条件信息,需要外面进行条件判断,这个条件通常是多个线程或进程的共享变量,因此必须对共享变量加上互斥锁

4. 读写锁

在任何时刻只能有一个线程访问资源,获取锁操作失败时,不会进入睡眠,而是原地自旋,直到锁被释放,这样节省了线程从睡眠到被唤醒的时间消耗,提高效率。

5. 自旋锁

当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环,避免类似互斥锁进入睡眠状态,省去唤醒的开销

三、补充

1. 死锁与活锁

死锁:指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象

死锁原理图

产生原因

(1)互斥条件:进程对所分配到的资源不允许其他进程访问,若其他进程访问,只能等待,直到占有该资源的进程使用完成后释放该资源

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

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

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

解决办法

(1)请求保持:资源一次性分配

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

(3)环路等待:资源按序号递增,进程请求按递增请求,释放则相反

活锁: 线程1可以使用资源,它让其他线程先使用资源,线程2也可以使用资源,它让其他线程先使用资源,最后两个线程都无法使用资源

2. 公平锁与非公平锁

公平锁:在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会按照FIFO的规则从队列中取到自己

非公平锁:直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式

注意:非公平锁的优点在于吞吐量比公平锁大

3. 乐观锁与悲观锁

乐观锁:假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,乐观锁适用于多读的应用类型,这样可以提高吞吐量
乐观锁适用于写比较少的情况下(多读场景)

悲观锁:假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁,悲观算适用于共享资源,每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程
悲观锁适用于写比较多的情况下(多写场景)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值