3.3 如何使用条件变量我们对「2.3」中的函数 func2 做个简单的修改:
#define MAX 3void *func2(void *arg){ pthread_mutex_lock(&mutex); puts("线程 th2 抢到锁,开始执行 giNum *= 2"); int i; for (i = 1; i <= MAX; i++) { giNum *= 2; } pthread_mutex_unlock(&mutex); return NULL;}对 func2() 做了个微小的改动:将giNum++修改为了giNum *= 2 。
这样的话,线程抢到锁的顺序不同会影响giNum的最终结果:
- th1 先抢到锁:giNum 先执行加操作,然后在执行乘操作,最终结果为 24
- th2 先抢到锁:giNum 先执行乘操作,然后在执行加操作,最终结果为 3
文章插图
如果如何才能做到线程 th1 总是能够先抢到锁呢?下面我们通过条件变量的方式来实现这一想法 。
#include <stdio.h>#include <pthread.h>#include <unistd.h>#define MAX 3#define TRUE 1#define FALSE 0int giNum = 0;int giFlag = FALSE; // TRUE:执行线程 2 的乘操作pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态初始化锁pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 静态初始化条件变量void *func1(void *arg){ pthread_mutex_lock(&mutex); puts("线程 th1 抢到锁"); puts("线程 th1 开始执行 giNum++"); int i; for (i = 1; i <= MAX; i++) { giNum++; } giFlag = TRUE; // 修改 giFlag 的值,使得线程 th2 满足条件 pthread_cond_signal(&cond); // 向线程 th2 发出信号 pthread_mutex_unlock(&mutex); return NULL;}void *func2(void *arg){ pthread_mutex_lock(&mutex); puts("线程 th2 抢到锁"); while (FALSE == giFlag) // 不满足线程 th2 的执行条件 { puts("线程 th2 不满足条件,等待~"); pthread_cond_wait(&cond, &mutex); // 等待被触发 } puts("线程 th2 满足条件,开始执行 giNum *= 2"); int i; for (i = 1; i <= MAX; i++) { giNum *= 2; } pthread_mutex_unlock(&mutex); return NULL;}int main(){ pthread_t th1; pthread_create(&th1, NULL, func1, NULL); pthread_t th2; pthread_create(&th2, NULL, func2, NULL); pthread_join(th1, NULL); pthread_join(th2, NULL); printf("giNum = %d\n", giNum); return 0;}
经验总结扩展阅读
- 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 题解