线程同步之条件变量

来源:互联网 发布:c语言打印时间间隔 编辑:程序博客网 时间:2024/04/25 06:51

进程空间中有一个存储量A,该进程空间内存在多个线程,这多个线程都会访问到A,或读或写,为了保障每个线程当前读到的是正确的A而不是别的线程正在修改过程中的A,我们在访问A之前需要对A进行加锁,使得我们在访问A的时候别的线程禁止访问A,这是互斥量锁。或者允许多个线程同时读A,这是读写锁。还有一种情况,有些线程也需要访问A,但是它只是想在A达到某个值的时候才做一些事情,即值关心达到某种状态下的A。比如线程1对A+1,线程2对A+1,线程3是检查A是否到达10才做一些操作。如果按照互斥量的方法,代码应该如下:


void *task1(void *arg){while(1){pthread_mutex_lock(&mutex);A++;pthread_mutex_unlock(&mutex);}}void *task1(void *arg){while(1){pthread_mutex_lock(&mutex);A++;pthread_mutex_unlock(&mutex);}}void *task3(void *arg){while(1){pthread_mutex_lock(&mutex);if(A >= 10){/*do work*/pthread_mutex_unlock(&mutex);}elsepthread_mutex_unlock(&mutex);}}

在线程3中,我们需要循环对A进行加锁判断其值是否达到10,其实在绝大部分的一段时间内A都不是10的,也就是说线程3将花费大量的时间来判断(else部分)。有一种解决方法是在线程3里面加上一个sleep,让线程3先休眠一会。但是可能在休眠之后A的值已经远远大于10了。因此也不行。于是我们想,为A配置一个条件变量,当有线程访问A的时候都就判断A是否达到10,如果达到就唤醒等待该条件变量的线程。而线程在运行的时候就告诉内核,我在等待条件变量来唤醒我。加上条件变量后的程序如下:


void *task1(void *arg){while(1){pthread_mutex_lock(&mutex);A++;pthread_mutex_unlock(&mutex);if(A >= 10)  //每次修改完判断pthread_cond_signal(&condition);}}void *task1(void *arg){while(1){pthread_mutex_lock(&mutex);A++;pthread_mutex_unlock(&mutex);if(A >= 10)pthread_cond_signal(&condition);}}void *task3(void *arg){while(1){pthread_mutex_lock(&mutex);while(A < 10)  //如果进程运行开始A<10,则告诉内核等待条件变量{pthread_cond_wait(&condition, &mutex);}/*do work*/pthread_mutex_unlock(&mutex);}}


这里线程3调用pthread_cond_wait函数来等待被唤醒,此函数会对A解锁并且进入阻塞。


下面是一个完整的测试程序:

#include <pthread.h>#include <stdio.h>#include "error.c"int count = 0;pthread_mutex_t mutex1;pthread_t tid1, tid2, tid3, tid4;pthread_cond_t condCount;void *task1(void *arg){while(1){printf("this is thread 1\n");pthread_mutex_lock(&mutex1);count++;printf("count is %d\n", count);pthread_mutex_unlock(&mutex1);if(count >= 10)pthread_cond_signal(&condCount);sleep(1);}pthread_exit((void*)1);}void *task2(void *arg){while(1){printf("this is thread 2\n");pthread_mutex_lock(&mutex1);count++;printf("count is %d\n", count);pthread_mutex_unlock(&mutex1);if(count >= 10)pthread_cond_signal(&condCount);sleep(1);}pthread_exit((void*)2);}void *task3(void *arg){while(1){printf("this is thread3\n");pthread_mutex_lock(&mutex1);count++;printf("count is %d\n", count);pthread_mutex_unlock(&mutex1);if(count >= 10)pthread_cond_signal(&condCount);sleep(1);}pthread_exit((void*)3);}void *task4(void *arg){while(1){printf("this is thread4\n");pthread_mutex_lock(&mutex1);while(count < 10){pthread_cond_wait(&condCount, &mutex1);}printf("count = %d\n", count);pthread_cancel(tid1);pthread_cancel(tid2);pthread_cancel(tid3);pthread_mutex_unlock(&mutex1);pthread_exit((void*)4);}pthread_exit((void*)4);}void main(){pthread_mutex_init(&mutex1, NULL);pthread_cond_init(&condCount, NULL);pthread_create(&tid1, NULL, task1, NULL);pthread_create(&tid2, NULL, task2, NULL);pthread_create(&tid3, NULL, task3, NULL);pthread_create(&tid4, NULL, task4, NULL);//sleep(1);void *tret;pthread_join(tid4, &tret);exit(0);}

这里解释一下,每个线程处理函数里面加上sleep的原因是,线程并发执行,每个线程分配的时间片内运行while的话会循环非常多此,这会导致结果太长不明显。

0 0
原创粉丝点击