第一种方法仅局限于静态初始化的时候使用:将「声明、定义、初始化」一气呵成,除此之外的情况都只能使用 pthread_mutex_init函数 。2.2 pthread_mutex_init函数原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
头 文 件:#include <pthread.h>
返 回 值:成功返回 0,失败返回错误码
参数介绍:
- mutex:指向 pthread_mutex_t 声明的变量的地址
- attr:指定了新建互斥锁的属性 。一般置为 NULL(如果参数attr为 NULL,则使用默认的互斥锁属性,默认属性为快速互斥锁 ) 。
restrict 关键字只用于限制指针 。告诉编译器所有修改该指针指向内存中的操作,只能通过本指针完成,不能通过除了本指针之外的变量或指针修改 。当我们通过 pthread_mutex_init() 初始化互斥量后,接下来就是上锁(pthread_mutex_lock)和解锁(pthread_mutex_unlock)操作了 。
2.3 上锁 & 解锁
上锁解锁函数原型pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);头 文 件#include <pthread.h>#include <pthread.h>返 回 值成功返回 0,失败返回错误码成功返回 0,失败返回错误码让我们来梳理一下互斥量的使用流程:
- 通过 pthread_mutex_init() 购买一把锁
- 通过 pthread_mutex_lock() 加锁
- 通过 pthread_mutex_unlock() 解锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态初始化锁void *func1(void *arg){ pthread_mutex_lock(&mutex); puts("线程 th1 抢到锁"); puts("线程 th1 开始执行 giNum++"); int i; for (i = 1; i <= MAX; i++) { giNum++; } pthread_mutex_unlock(&mutex); return NULL;}void *func2(void *arg){ pthread_mutex_lock(&mutex); puts("线程 th2 抢到锁"); puts("开始执行 giNum++"); int i; for (i = 1; i <= MAX; i++) { giNum *= 2; } pthread_mutex_unlock(&mutex); return NULL;}此时,再次运行程序,你会发现不管运行多少次,结果都是 \(giNum = 2\times10^7\) 。
下面我们对上面的代码做个简单的修改,将 func2 中的giNum++操作修改为giNum *= 2,
三、条件变量3.1 为什么要使用条件变量如果没有条件变量,那么我们等待一个条件满足则会是下面这样的模型:

文章插图
- 首先加锁进入临界区去查看条件是否满足,不满足则解锁离开临界区,睡眠一段时间再继续循环判断 。
经验总结扩展阅读
- VLQ & Base64 VLQ 编码方式的原理及代码实现
- MYSQL-->InnoDB引擎底层原理
- StampedLock:一个并发编程中非常重要的票据锁
- Longchamp龙骧饺子包
- <三>从编译器角度理解C++代码编译和链接原理
- <一>关于进程虚拟地址空间区域内存划分和布局
- GitLab私有化部署 - CI/CD - 持续集成/交付/部署 - 源代码托管 & 自动化部署
- 🔥支持 Java 19 的轻量级应用开发框架,Solon v1.10.4 发布
- Bert不完全手册9. 长文本建模 BigBird & Longformer & Reformer & Performer
- XXI Open Cup, Grand Prix of Belarus 2020-2021 Winter Petrozavodsk Camp, Belarusian SU Contest 题解
