8.条件变量应用实例

来源:互联网 发布:尼尔森数据查询 编辑:程序博客网 时间:2024/05/03 02:20

基于《4.Linux C多线程的执行顺序问题》进行修改,现在要做这么一件事情,线程thread_one和线程thread_two共同处理一个全局变量i,thread_one:++i和打印i,thread_two处理的事情是:打印i。thread_one和thread_two都处理打印i的事务,所不同的是,当i为3的倍数的时候,由thread_two打印,否则由thread_one打印。

程序如下:

#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>static void thread_one(char* msg);static void thread_two(char* msg);pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int i = 1;int temp;int main(int argc, char** argv){pthread_t th_one, th_two;char * msg = "thread";printf("thread_one starting\n");if (pthread_create(&th_one, NULL, (void*)&thread_one, msg) != 0) {exit(EXIT_FAILURE);}printf("thread_two starting\n");if (pthread_create(&th_two, NULL, (void*)&thread_two, msg) != 0) {exit(EXIT_FAILURE);}pthread_join(th_one, NULL);pthread_join(th_two, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);printf("Main thread is going over!\n");return 0;}static void thread_one(char* msg){int j = 0;while (i < 10) {pthread_mutex_lock(&mutex);if (i % 3 == 0) {temp = i;i++;pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);usleep(10);// 为了让thread_two有足够执行时间,10ms} else {printf("I am one. loop %d\n", i);i++;pthread_mutex_unlock(&mutex);}}printf("one is over!\n");}static void thread_two(char* msg){int j = 0;while (i < 10) {pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);pthread_mutex_unlock(&mutex);printf("I am two. loop %d\n", temp);}printf("two is over!\n");}
编译执行结果如下:

root@book-desktop:/opt/pc_test/multithreading/t# ./main 

thread_one starting

thread_two starting

I am one. loop 1

I am one. loop 2

I am two. loop 3

I am one. loop 4

I am one. loop 5

I am two. loop 6

I am one. loop 7

I am one. loop 8

I am two. loop 9

two is over!

one is over!

Main thread is going over!

先来分析“pthread_cond_wait(&cond, &mutex);”

可以说是pthread_cond_wait()是条件变量机制中的最重要也是最难分析的函数。

使用条件变量机制直观上比较简单:调用pthread_cond_wait()的线程把自个儿给阻塞起来,然后等待别的线程调用pthread_cond_signal()把它唤醒。

pthread_cond_wait(&cond,&mutex)操作有两步,是原子操作:第一步是解锁,先解除之前的pthread_mutex_lock()锁定的mutex;第二步是挂起,阻塞并在等待对列里休眠,即线程thread_two挂起,直到被线程thread_one再次被唤醒,唤醒的条件是由“pthread_cond_signal(&cond);”发出的cond信号来唤醒。(这段话来自网络,总感觉有些问题,但我得明白pthread_mutex_lock()涉及两次mutex操作:上锁和解锁)

值得注意的是,pthread_cond_wait函数的使用方法如下:

pthread_mutex_lock(&mutex); // step a

pthread_cond_wait(&cond, &mutex); // step b

pthread_mutex_unlock(&mutex); // step c

step a比较容易理解了,step c如何理解呢?

这得深刻解剖pthread_cond_wait()了,先看线程thread_two是如何进入阻塞状态的:

a.解锁(解除step a锁定的mutex,如此使得与之共享锁的线程譬如thread_one能够拥有该mutex)、等待(阻塞睡眠之类的,此阻塞发生在pthread_cond_wait函数内部)。

b....等待,直到pthread_cond_signal()函数唤醒之。

c.此时被唤醒的线程上下文仍然在pthread_cond_wait函数内部,此时加锁,使得mutex被线程thread_two重新拥有,然后处理返回值之类的。

所以上面的step a、b、c可以解剖为如下这般:

a------- pthread_mutex_lock(&mutex);

b1------- pthread_mutex_unlock(&mutex);

睡眠............唤醒

b2------- pthread_mutex_lock(&mutex);

c------- pthread_mutex_unlock(&mutex);

理解“pthread_cond_wait(&cond, &mutex);”有两个关键:

1.pthread_cond_wait函数涉及两次mutex操作;

2.pthread_cond_wait函数并不是1次原子操作,线程阻塞于此函数内部,同样线程也是在此函数内部被唤醒。

接着来分析“pthread_cond_signal(&cond);”

关于pthread_cond_signal(),网文曰:

“pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行。如果没有线程处在阻塞等待状态,pthread_cond_signal()也会成功返回。”

“使用pthread_cond_signal函数不会有‘惊群现象’产生,他最多只给一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个pthread_cond_signal()最多发信号一次。”

需要注意的是pthread_cond_signal函数不涉及mutex的操作,所以在thread_one里调用pthread_cond_signal函数,thread_two只能说被唤醒,但此时mutex还未被释放掉,也即thread_two的程序还不能被执行,直到thread_one释放掉mutex为止。

上文已经提到,对于pthread_cond_wait()的使用方法,大概如下:

pthread_mutex_lock(&mutex); // step a

pthread_cond_wait(&cond, &mutex); // step b

pthread_mutex_unlock(&mutex); // step c

事实上,若需要在thread_two中处理共同资源,最好如下般这样:

pthread_mutex_lock(&mutex); // step a

pthread_cond_wait(&cond, &mutex); // step b

...处理共享数据 // step c

pthread_mutex_unlock(&mutex); // step d

同样,对于pthread_cond_signal()的使用方法,也可以如下般这样:

pthread_mutex_lock(&mutex); // step a

pthread_cond_signal(&cond, &mutex); // step b

...处理共享数据 // step c

pthread_mutex_unlock(&mutex); // step d

本文程序并不是一个多么好的条件变量的应用实例,但通过它足以体会条件变量的使用方法~

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 文学社在社团活动日可以怎么办 小孩玩游戏瞎花钱怎么办 党员不配合纪检调查工作怎么办 新同事老问问题怎么办 白色衣服染红色了怎么办 左腿膝盖内侧疼怎么办 差二本线几分怎么办 吃错东西了想吐怎么办 玩游戏扣的话费怎么办 转笔实在是不会怎么办 滑板l轴承沾水了怎么办 暗影格斗3闪退怎么办 暗影格斗3文档被删怎么办 dnf手残党偷学技能学不了怎么办 打篮球没热身膝盖酸痛是怎么办 无线路由器lan口少怎么办? 电脑ip设置乱了怎么办 监控拍我我偷钱怎么办 网吧上网密码忘记了怎么办 比熊犬晚上叫怎么办 刚买的狗一直叫怎么办 酒驾罚款2年没交怎么办 法院判罚款没有钱怎么办 有人朝你吐口水怎么办 孕妇用了六神花露水怎么办 出车祸人不赔钱怎么办 交通事故对方保险不签字怎么办 肇事车主联系不上怎么办 商标被别人申请无效宣告怎么办 淘宝上传宝贝没有品牌怎么办 萌虎白卡借款2000逾期了怎么办 最里面的牙齿烂了怎么办 金龙沉底不游怎么办 龙鱼尾巴烂了怎么办 微博忘了登录名和密码怎么办 新浪微博密码忘了怎么办 vivo手机用户密码忘了怎么办 微博登录名忘记了怎么办 微信忘记密码钱怎么办 微信密码申诉失败怎么办 微博密码被盗了怎么办