条件变量

同步保证了各个执行流对临界资源访问的合理性
当有资源的时候可以直接获得资源,没有资源进行线程等待,等待另一个线程生产资源,然后通知等待线程。

条件变量:
本质= 两个接口(等待接口+唤醒接口) + PCB等待队列
接口:
1.定义条件变量
pthread_cond_t
2.初始化:
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrictattr);

3.销毁
int pthread_cond_destroy(pthread_cond_t *cond);
4.等待接口(下面该接口重点分析)
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
5.唤醒接口
//唤醒PCB等待队列所有执行流
int pthread_cond_broadcast(pthread_cond_t *cond);
//唤醒PCB等待队列至少一个执行流
int pthread_cond_signal(pthread_cond_t *cond);

示例:
在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#define THREADCOUNT 2
//0代表当前碗里没有面
//1代表碗里有面
int g_noodle = 0;

pthread_mutex_t lock;
pthread_cond_t consume_cond;
pthread_cond_t product_cond;

void* ConsumeStart(void* arg)
{
    (void)arg;
    while(1)
    {
        pthread_mutex_lock(&lock);
        while(g_noodle == 0)
        {
            //阻塞等
            //1.将该PCB放到PCB等待队列当中去
            //2.解锁
            //3.等待被唤醒
            pthread_cond_wait(&consume_cond, &lock);
        }
        g_noodle--;
        printf("i am Consumer i Consume %d\n", g_noodle);
        pthread_mutex_unlock(&lock);
        //通知厨子,有可能在唤醒之后,还是厨子拿到了互斥锁,判断了碗里还是有面的,所以厨子被放到了PCB等待队列当中去了,所以说我们需要吃碗面的时候,通知一下PCB等待队列当中的线程
        pthread_cond_signal(&product_cond);
    }
    return NULL;
}

void* ProductStart(void* arg)
{
    (void)arg;
    while(1)
    {
        pthread_mutex_lock(&lock);
        while(g_noodle == 1)
        {
            pthread_cond_wait(&product_cond, &lock);
        }
        g_noodle++;
        printf("i am Producer i product %d\n", g_noodle);
        pthread_mutex_unlock(&lock);
        pthread_cond_signal(&consume_cond);
    }
    return NULL;
}

int main()
{
    pthread_mutex_init(&lock, NULL);
    pthread_cond_init(&consume_cond, NULL);
    pthread_cond_init(&product_cond, NULL);
    pthread_t Consume_tid[THREADCOUNT];
    pthread_t Product_tid[THREADCOUNT];
    //pthread_t tid[2];
    int i = 0;
    int ret = -1;
    for(; i < THREADCOUNT; i++)
    {
        ret = pthread_create(&Consume_tid[i], NULL, ConsumeStart, NULL);
        if(ret < 0)
        {
            perror("pthread_create");
            return 0;
        }
    }

    for(i = 0; i < THREADCOUNT; i++)
    {
        ret = pthread_create(&Product_tid[i], NULL, ProductStart, NULL);
        if(ret < 0)
        {
            perror("pthread_create");
            return 0;
        }
    }

    for(int i = 0; i < THREADCOUNT; i++)
    {
        pthread_join(Consume_tid[i], NULL);
        pthread_join(Product_tid[i], NULL);
    }

    pthread_mutex_destroy(&lock);
    pthread_cond_destroy(&consume_cond);
    pthread_cond_destroy(&product_cond);
    return 0;
}

等待接口:
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
1.为什么要使用互斥锁
因为同步只是保证各个执行流对临界资源访问的合理性,并没有保证各个执行流对临界资源访问的互斥属性。
所以需要使用当前条件变量条件变量和互斥锁同时使用,保证同步+互斥
2.该接口内部逻辑实现
2.1.将调用者的PCB放到PCB等待队列当中
2.2.对互斥锁进行解锁
2.3.等待被唤醒
2.3.1.如果被其他执行流唤醒,需要移出PCB等待队列
2.3.2.对互斥锁进行加锁
2.3.2.1.加锁成功,pthread_cond_wait返回
2.3.2.2.加锁失败阻塞在pthread_cond_wait接口内部加互斥锁的逻辑中
2.3.2.2.1.拥有CPU资源继续加锁操作,知道加锁成功pthread_cond_wait返回
2.3.2.2.2.时间片到了,被迫让出CPU资源,在程序计数器和上下文信息中保存当前抢锁的指令和变量的值
3.pthread_cond_wait为什么要先将调用者的PCB放到PCB等待队列才进行释放互斥锁
防止消费线程提前释放互斥锁,生产线程抢在消费线程进行PCB等待之前抢到了所资源,并执行生成逻辑后,而这个时候将
消费线程放到PCB等待队列当中,就可能造成没有生产线程去调用pthread_cond_broadcast/signal(pthread_cond_t *cond)这样
的接口来唤醒PCB等待队列了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值