进程空间中有一个存储量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);
}
else
pthread_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);
}
}
下面是一个完整的测试程序:
#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的话会循环非常多此,这会导致结果太长不明显。