Linux 同步机制:条件变量

版权声明:转载请声明 https://blog.csdn.net/qq_40732350/article/details/82720620

讲条件变量之前,要先讲互斥量(也称互斥锁)

1.互斥锁:

我把它比作厕所的门,只能有一个人通过 打开这个门使用CPU(或变量),(当然可以有多个厕所门)

就上厕所一样,不可能两个人打开一个门,然后一起蹲同一个坑,

当一个人检查到门打开着,就会进去,然后关门,另一个人,想上厕所只能一直等门打开

假设下面这样的情景:

  1. 线程1和线程2要读变量BUF,线程3写BUF,线程3没写BUF之前,BUF为空
  2. 线程1要想读,就得不停得检测BUF为不为空,检测到不为空后,然后加锁,然后读,然后释放锁
  3. 线程2和线程1一样
  4. 线程3写完BUF后,要设置  标志  然后释放锁

注意:线程1和线程2检测的方法是

while(标志 != 我们设定的值)

{

     加锁

     读取

     释放锁

}

缺点:

  1. 要不停的检测标志位,浪费CPU
  2. 单纯的使用标志位,有时不能很好的通知所有要读标志的线程
  3.  

由于上面的情况(当然我所展示的可能不全),采用了条件变量

 

2.条件变量:

条件变量其实是用于实现生产者和消费者的问题

  1. 消费者线程启动,获取互斥量读缓冲区,发现为空,阻塞自己并同时释放互斥量;
  2. 生产者线程启动,获取互斥量写缓冲区,写完毕后,通知消费者同时释放互斥量;
  3. 消费者线程唤醒,获取互斥量读缓冲区;

注意:

当一个线程加了互斥锁后,然后等待条件变量时,会先释放互斥锁

当收到条件变量通知后,又会获得锁,然后还得释放锁,其他需要锁的线程才能运行

条件变量的相关函数:

//使用初始化函数:
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict
attr);
//条件变量的销毁函数
int pthread_cond_destroy(pthread_cond_t *cond);
//条件变量等待函数
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

//条件变量唤醒函数
int pthread_cond_broadcast(pthread_cond_t *cond);  //通知所有消费者
int pthread_cond_signal(pthread_cond_t *cond);   //只能唤醒其中任意一个消费者

两个等待函数的区别:

pthread_cond_timedwait()比pthread_cond_wait()函数多了一个参数abstime,此参数可以设定等待超时,

如果达到abstime所指定的时刻,仍然没有别的线程来唤醒当前线程,就返回ETIMEDOUT。

实例代码:

两个读线程,一个写线程

写线程写完后,那两个才能读

#include <pthread.h>
#include <stdio.h>
#include <string.h>

char buff[100];
int buff_len;
pthread_mutex_t mutex;
pthread_cond_t cond;

void* th_writer(void *p)
{
    pthread_mutex_lock(&mutex);
    strcpy(buff, "hello, world!");
    buff_len = strlen(buff);
    printf("func[%s]: %s\n", __FUNCTION__, buff);
    sleep(1);
    //pthread_cond_signal(&cond); // signal 只能唤醒一个消费者
    pthread_cond_broadcast(&cond); // 通知所有消费者
    pthread_mutex_unlock(&mutex);  // 释放缓冲区,共享的数据区
	pthread_exit( (void *)0 );
}

void* th_reader1(void *p)
{
    pthread_mutex_lock(&mutex);
    if (buff_len == 0) {
        printf("func[%s]: buff empty, block\n", __FUNCTION__);
        pthread_cond_wait(&cond, &mutex); // 原子调用阻塞,并解锁其互斥量
    }

    printf("func[%s]: %s\n", __FUNCTION__, buff);
    sleep(1);
    pthread_mutex_unlock(&mutex);
	pthread_exit( (void *)0 );
}

void* th_reader2(void *p)
{
    pthread_mutex_lock(&mutex);
    if (buff_len == 0) {
        pthread_cond_wait(&cond, &mutex); // 原子调用阻塞,并解锁其互斥量
        printf("func[%s]: buff empty, block\n", __FUNCTION__);
    }
    printf("func[%s]: %s\n", __FUNCTION__, buff);
    sleep(1);
    pthread_mutex_unlock(&mutex);
	pthread_exit( (void *)0 );
}


int main()
{
    pthread_t tid1, tid2, tid3;
    void *ret1, *ret2, *ret3;
	
    memset(buff, 0, sizeof(buff));
	
    pthread_mutex_init(&mutex, NULL);  //互斥量初始化
	
    pthread_cond_init(&cond, NULL);   //条件变量初始化
	
    printf("start thread reader 1\n");
    pthread_create(&tid2, NULL, th_reader1, NULL);  //创建 读 线程1
    printf("wait 1s in main thread.\n");
	
    sleep(1);
	
    printf("start thread reader 2\n");
    pthread_create(&tid3, NULL, th_reader2, NULL);  //创建 读 线程2
	
    printf("start thread writer \n");
    pthread_create(&tid1, NULL, th_writer, NULL);   //创建 写 线程
	
    pthread_join(tid1, &ret1);
    pthread_join(tid2, &ret2);
    pthread_join(tid3, &ret3);
    pthread_mutex_destroy(&mutex);  //销毁互斥量
    pthread_cond_destroy(&cond);   //销毁条件变量
    return 0;
}

结果:

# ./a.out 
start thread reader 1
wait 1s in main thread.
func[th_reader1]: buff empty, block
start thread reader 2
start thread writer 
func[th_writer]: hello, world!
func[th_reader1]: hello, world!
func[th_reader2]: buff empty, block
func[th_reader2]: hello, world!

猜你喜欢

转载自blog.csdn.net/qq_40732350/article/details/82720620