线程同步之条件变量

进程空间中有一个存储量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);
	}
}


这里线程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的话会循环非常多此,这会导致结果太长不明显。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值