当前位置:网站首页 > C++编程 > 正文

gmock原理(gmock doall)



前段实践在B站进行模拟面试时发现,
模拟面试第四期-已经拿到大厂OFFER的研究生大佬-LINUX卷到飞起
自己对Linux中的同步互斥方法,以及IPC方法,没有很好的理解和总结过。因此,本笔记将总结这部分内容。

内核线程进程机制原子操作、自旋锁、信号量、互斥量互斥量、读写锁、条件变量、信号量(有些书把信号量放在IPC通信里面,因为它可以被用于进程间通信同步)IPC:管道(无名管道)、FIFO(有名管道)、消息队列、信号(Signals)、共享内存、 套接字 (Sockets)特点提供了多种用于进程间通信和线程同步的 基础设施 协调同一进程中不同线程对共享数据的访问 在不同的进程之间传递数据

这个部分在Linux内核学习笔记中,已经做过关于内部实现的笔记。

Linux驱动-同步互斥与原子变量 - 认真学习的小诚同学

Linux驱动-内核锁的介绍与使用 - 认真学习的小诚同学

Linux驱动-内核自旋锁spinlock的实现 - 认真学习的小诚同学

Linux驱动-内核信号量semaphore的实现 - 认真学习的小诚同学

Linux驱动-内核互斥量mutex的实现 - 认真学习的小诚同学

这里做个总结:

内核锁分为

  • 自旋锁(无法获得锁时,当前线程原地等待):原始自旋锁(raw_spinlock_t)、位自旋锁(bit spinlocks)
  • 睡眠锁(无法获得锁时,当前线程就会休眠):互斥量、实时互斥锁、信号量、读写信号量等。
机制实现方式自旋锁UP(单CPU):支持抢占的系统,关闭调度器;不支持抢占的系统,本身就独占了
SMP(多核):使用原子操作ldrex和strex完成互斥信号量通过自旋锁lock和计数量count,以及一个等待队列(阻塞的线程放在其中)互斥量同样通过自旋锁lock和二值计数量count,以及一个等待队列(阻塞的线程放在其中)
实现了一个快速路径fastpath-在大部分情况下都可以直接在此获得或释放锁,所以互斥量比信号量的效率高

线程同步(synchronization)是指在一定的时间内只允许某一个线程访问某个共享资源。而在此时间内,不允许其它的线程访问该资源。

2.1 互斥量

从本质上来说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。

2.1.1 API
功能API描述创建int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);返回:若成功返回0,否则返回错误编号销毁int pthread_mutex_destroy(pthread_mutex_t mutex);返回:若成功返回0,否则返回错误编号加锁int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);返回:若成功返回0,否则返回错误编号;
调用pthread_mutex_lock,如果互斥量已经上锁, 调用线程阻塞直到互斥量被解锁。 如果不希望被阻塞,可以使用pthread_mutex_trylock 尝试加锁,无论成功都会返回。解锁int pthread_mutex_unlock(pthread_mutex_t *mutex);
2.1.2 死锁问题

死锁详解和解决办法_避免死锁的三种方法-CSDN博客

【并发 bug 和应对 (死锁/数据竞争/原子性违反;防御性编程和动态分析) 南京大学2022操作系统-P8】 【精准空降到 24:22】

死锁只有同时满足以下四个条件才会发生:

  • 互斥:一个资源每次只能被一个进程使用;
  • 持有并等待:一个进程请求资源阻塞时,不释放已获得的资源;
  • 不可剥夺:进程已获得的资源不能被强行剥夺;
  • 环路等待:若干进程之间形成头尾相接的循环等待资源关系。

解决方法就是经典的银行家算法

2.1.3 示例
 

2.2 读写锁

与互斥量类似,但读写锁允许更高的并行性。其特性为:写独占,读共享

适用场景:读写锁非常适合于对数据结构读的次数远大于写的情况。

2.2.1 API
功能API描述创建int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);返回:若成功返回0,否则返回错误编号销毁int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);返回:若成功返回0,否则返回错误编号加锁int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);返回:若成功返回0,否则返回错误编号;解锁int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
2.2.2 示例
 

2.3 信号量

可以理解为一个计数器,表示当前可用共享资源的数量。

  • 信号量基于操作系统的 PV 操作,对信号量的操作都是原子操作;
  • 信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数;
  • 支持信号量组;
  • 有两套信号量:System V 和 Semaphore
2.3.1 API

- System V 信号量

  1. 特性:
    • 属于System V IPC(进程间通信)。
    • 提供了一组复杂的功能,适合复杂的进程间同步控制。
    • 典型操作包括(获取/创建信号量)、(操作信号量)和(控制信号量集)。
    • 支持信号量集的概念,可以一次性操作多个信号量,适用于高级同步需求。
    • // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1

      // 控制信号量的相关信息

      // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1

  2. 使用场景:
    • 适用于需要细粒度、复杂同步的多进程应用程序。
    • 在需要跨越不同应用程序的持久性IPC时(System V信号量可以在系统重启后仍保持存在,直到显式删除)。
  3. 复杂性:
    • 相对复杂,使用起来需要理解其数据结构和操作指标。
    • 相关数据结构和操作通常需要更复杂的设置和管理。需要使用进行一些配置,这是标准的一个例外之处。

- POSIX 信号量

  1. 特性:
    • 属于POSIX标准。
    • 提供了更简单易用的信号量API。典型操作包括(初始化信号量)、(等待信号量)、(释放信号量)和(销毁信号量)。
    • 可以是命名信号量或无名信号量。命名信号量可以用于进程间同步,而无名信号量通常用于线程间同步。
  2. 使用场景:
    • 适用于进程间或线程间的简单同步。
    • 易于使用,集成到标准C库中,大多数现代系统都支持。
  3. 复杂性:
    • 易于使用和管理,适合需要简单同步机制的应用。
    • 不支持信号量集,但更适合于一般的多线程和多进程同步场景。
2.3.2 示例
 

2.4 条件变量

条件变量是一种同步机制,允许线程挂起,直到共享数据上的某些条件得到满足。

主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使“条件成立”.

为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起

2.4.1 API
2.4.2 示例
 

参考:一文搞懂六大进程通信机制原理(全网最详细)

3.1 管道

通常指无名管道。

  • 数据只能在一个方向上流动, 具有固定的读端和写端
  • 它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)
3.1.1 API
 

返回值:若成功则返回0,若出错则返回-1; 说明:由参数filedes返回两个文件描述符:filedes[0]为读而打开;filedes[1]为写而打开。

3.1.2 示例
 

3.2 FIFO

命名管道,它是一种文件类型。

  • FIFO可以在无关的进程之间交换数据,与无名管道不同。
  • FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中
 

返回值:成功返回0,出错返回-1;

其中的 mode 参数与open函数中的 mode 相同。一旦创建了一个 FIFO,就可以用一般的文件I/O函数操作它。

示例:

 
 

3.3 消息队列

消息队列就是消息的链表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。

  • 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级;
  • 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除;
  • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
3.3.1 API
 

在以下两种情况下,msgget将创建一个新的消息队列:

  1. 如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREATE
  2. key参数为IPC_PRIVATE

函数msgrcv在读取消息队列时,type参数有下面几种情况:

  1. type == 0,返回队列中的第一个消息;
  2. type > 0,返回队列中消息类型为 type 的第一个消息;
  3. type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。

服务端程序一直在等待特定类型的消息,当收到该类型的消息以后,发送另一种特定类型的消息作为反馈,客户端读取该反馈并打印出来

3.3.2 示例

服务端程序一直在等待特定类型的消息,当收到该类型的消息以后,发送另一种特定类型的消息作为反馈,客户端读取该反馈并打印出来。

 
 

3.4 信号

信号和信号量是完全不同的两个概念

3.4.1 有哪些信号
 

Linux 系统中有许多信号,其中前面 31 个信号都有一个特殊的名字,对应一个特殊的事件,这些信号都是从 Unix 系统继承下来的,他们还有个名称叫“不可靠信号”,他们有如下的特点:

  • 非实时信号不排队,信号的响应会相互嵌套。
  • 如果目标进程没有及时响应非实时信号,那么随后到达的该信号将会被丢弃。
  • 每一个非实时信号都对应一个系统事件,当这个事件发生时,将产生这个信号。
  • 如果进程的挂起信号中含有实时和非实时信号,那么进程优先响应实时信号并且会从大到小依此响应,而非实时信号没有固定的次序。

后面的 31 个信号(从 到 )是 Linux 系统新增的实时信号,也被称为“可靠信号”,这些信号的特征是:

  • 实时信号的响应次序按接收顺序排队,不嵌套。
  • 即使相同的实时信号被同时发送多次,也不会被丢弃,而会依次挨个响应。
  • 实时信号没有特殊的系统事件与之对应
    在这里插入图片描述

对以上信号,需要着重注意的是:

1,上表中罗列出来的信号的“值”,在 平台下是有效的,但是别的平台的信号值也许跟这个表的不一致。

2,“备注”中注明的事件发生时会产生相应的信号,但并不是说该信号的产生就一定发生了这个事件。事实上,任何进程都可以使用函数 来产生任何信号。

3,信号 和 是两个特殊的信号,他们不能被忽略、阻塞或捕捉,只能按缺省动作来响应

换句话说,除了这两个信号之外的其他信号,接收信号的目标进程按照如下顺序来做出反应:

A) 如果该信号被阻塞,那么将该信号挂起,不对其做任何处理,等到解除对其阻塞为止。否则进入B。

B) 如果该信号被捕捉,那么进一步判断捕捉的类型:

​ B1) 如果设置了响应函数,那么执行该响应函数。

​ B2) 如果设置为忽略,那么直接丢弃该信号。

​ 否则进入C。

C) 执行该信号的缺省动作

3.4.2 API
  1. 函数
    • 用于设置一个简单的信号处理器。
    • 原型:
    • 使用时,指定要捕获的信号以及处理信号的函数。
  2. 函数
    • 提供了更强大和灵活的信号处理设置。
    • 原型:
    • 可以将的设置为来忽略信号或恢复默认处理。
    • 提供了一种可靠的方法来设置信号处理程序,并支持更多功能,如信号阻塞集。
  3. 函数
    • 发送信号给调用进程本身。
    • 原型:
    • 实际上相当于调用 。
  4. 函数
    • 发送信号给指定进程。
    • 原型:
    • 可以用来向一个或多个进程发送信号。

……

3.5 共享内存

3.5 共享内存

指两个或多个进程共享一个给定的存储区.

  • 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取
  • 因为多个进程可以同时操作,所以需要进行同步
  • 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问
    在这里插入图片描述
3.5.1 API
 

当用shmget函数创建一段共享内存时,必须指定其size;而如果引用一个已存在的共享内存,将size 指定为0。

当一段共享内存被创建以后,它并不能被任何进程访问。必须使用shmat函数连接该共享内存到当前进程的地址空间,随后可以访问。

shmdt函数是用来断开shmat建立的连接的。注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。

shmctl函数可以对共享内存执行多种操作,根据参数 cmd 执行相应的操作。常用的是IPC_RMID(从系统中删除该共享内存)。

3.5.2 示例

【共享内存+信号量+消息队列】:

  1. 消息队列将用于初始化通信。在这种情况下,客户端可以请求服务,同时也可以用来通知服务器有新的请求需要处理。
  2. 共享内存将作为数据交换的主要手段,因为它允许两个进程共享和访问同一内存段。
  3. 信号量用于同步,以便控制对共享内存的访问,防止竞态条件。
 
 

3.6 套接字

Socket支持不同主机上的两个进程IPC。这里不详细介绍了,可以参考网络编程相关知识。

在这里插入图片描述

到此这篇gmock原理(gmock doall)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • msvcp140.dll找不到的解决方法(msvcp120.dll找不到的解决方法)2025-02-08 08:27:05
  • plc1200定时器有几种(plc1200定时器的用法)2025-02-08 08:27:05
  • msvcp140.dll无法继续执行代码(msvcp100.dll无法继续执行代码)2025-02-08 08:27:05
  • cmake 多文件夹(cmake 多个文件 多个目录)2025-02-08 08:27:05
  • 数组方法find(数组方法slice)2025-02-08 08:27:05
  • cnnsa是哪个港口(cnnsh港口)2025-02-08 08:27:05
  • dhclient获取ip(dhcp获取ip)2025-02-08 08:27:05
  • pointnet++代码详解(pointrcnn代码)2025-02-08 08:27:05
  • can通讯接口(can通信接口)2025-02-08 08:27:05
  • Nvim 转码(ncm转码 安卓)2025-02-08 08:27:05
  • 全屏图片