何时使用条件变量? 我们有互斥锁不是就够了么?

先来看看两者的概念:

互斥锁是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制。

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。


为什么要有条件变量呢?我们有互斥量不是就够了么? 条件变量为什么要和互斥锁一块儿使用呢?


下面我们来看一个例子:

假设有共享的资源sum,与之相关联的mutex 是lock_s.假设每个线程对sum的操作很简单的,与sum的状态无关,比如只是sum++.那么只用mutex足够了.程序员只要确保每个线程操作前,取得lock,然后sum++,再unlock即可.每个线程的代码将像这样

add()
{
  pthread_mutex_lock(lock_s);
  sum++;
  pthread_mutex_unlock(lock_s);
}

从这个例子中可以看出好像我们使用互斥锁就完全可以完成我们的任务了,但是如果条件发生变化,我们要在sum的值大于100的时候将sum清零,此时该怎么做呢?例如下面的例子

假设线程t0,t1,t2的操作是sum++,而线程t3则是在sum大于100的时候,打印出一条信息,并对sum清零.

方案一:轮询,每次都lock->检查sum的值->unlock,当sum>100的时候,对sum进行清零

方案二:间歇性扫描,lock->检查sum的值->不大于100->sleep(某个值)->睡醒时候继续该过程,直到sum>100的时候,将sum清零.

方案一显然太low, 方案二的代码如下:

这个时候,t0,t1,t2的代码不变,t3的代码如下

print()
{
	while (1)
	{
		pthread_mutex_lock(lock_s);
		if(sum>100)
		{
			printf(“sum reach 100!”);
			sum = 0;
			pthread_mutex_unlock(lock_s);
		}
		else
		{
			pthread_mutex_unlock(lock_s);
			my_thread_sleep(100);
			return OK;
		}
	}
}


方案一的问题在于由于不断地轮询,lock/unlock会耗费大量的cpu时间,而且大多数情况下sum的值并不满足要求,做的都是无用功.

方案二的问题在于sleep()要睡眠多长时间呢,时间太短的话,会出现和方案一同样的问题,时间太长的话,sum到达100的时候又没有及时响应,可能等你响应的时候,sum已经远远大于100.


如何解决这个问题呢? 当你叫焦头烂额的时候,条件变量condition variable内裤外穿,从天而降!!!拯救了你.

你首先定义一个condition variable.
  

pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;
//t0,t1,t2的代码只要后面加两行,像这样
add()
{
	pthread_mutex_lock(lock_s);
	sum++;
	pthread_mutex_unlock(lock_s);
	if(sum>100)
	{
		pthread_cond_signal(&cond_sum_ready);
	}
}
//而t3的代码则是
print()
{
	pthread_mutex_lock(lock_s);
	while(sum<100)
	{
		pthread_cond_wait(&cond_sum_ready, &lock_s);
		printf(“sum is over 100!”);
		sum=0;
		pthread_mutex_unlock(lock_s);
		break;
	}
	return OK;
}

注意:

  在thread_cond_wait()之前,必须先lock相关联的mutex,因为假如目标条件未满足,pthread_cond_wait()实际上会unlock该mutex, 然后block,在目标条件满足后再重新lock该mutex, 然后返回.




条件变量互斥锁都是多线程编程中用于同步和互斥的机制,但它们有不同的用途和特点。 1. **互斥锁(Mutex)**: - **用途**:互斥锁用于保护共享资源,确保同一时间只有一个线程可以访问共享资源。 - **工作原理**:当一个线程获取到互斥锁后,其他线程必须等待,直到该线程释放互斥锁。 - **使用场景**:适用于保护短时间的临界区,确保对共享资源的原子访问。 2. **条件变量(Condition Variable)**: - **用途**:条件变量用于线程间的通信,允许一个线程等待特定条件成立,而另一个线程在条件满足时通知等待的线程。 - **工作原理**:线程在条件变量上等待(wait)时,会释放互斥锁并进入阻塞状态,直到其他线程在条件变量上发出信号(signal)或广播(broadcast),唤醒等待的线程。 - **使用场景**:适用于需要线程间同步和等待特定条件的场景,如生产者-消费者问题。 ### 区别 - **功能不同**:互斥锁用于保护共享资源,防止竞争条件;条件变量用于线程间的通信和同步。 - **使用方式不同**:互斥锁通过加锁和解锁来保护临界区;条件变量通过等待和信号机制来实现线程间的同步。 ### 示例 ```c #include <pthread.h> #include <stdio.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int count = 0; void* producer(void* arg) { while (1) { pthread_mutex_lock(&mutex); count++; printf("Produced: %d\n", count); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); sleep(1); } return NULL; } void* consumer(void* arg) { while (1) { pthread_mutex_lock(&mutex); while (count == 0) { pthread_cond_wait(&cond, &mutex); } printf("Consumed: %d\n", count); count--; pthread_mutex_unlock(&mutex); sleep(1); } return NULL; } int main() { pthread_t prod_thread, cons_thread; pthread_create(&prod_thread, NULL, producer, NULL); pthread_create(&cons_thread, NULL, consumer, NULL); pthread_join(prod_thread, NULL); pthread_join(cons_thread, NULL); return 0; } ``` 在这个示例中,生产者线程通过互斥锁保护共享资源`count`,并在满足条件时通过条件变量通知消费者线程。消费者线程在条件不满足时等待条件变量
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值