线程的同步-条件变量

线程的同步

线程为了实现同步专门引入一种机制叫做条件变量,当然线程实现同步还有其它方式如互斥锁信号量等!

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

条件变量和互斥锁的使用非常类似,互斥锁的用法在我的博客中也有详细讲解(https://blog.csdn.net/weixin_48617416/article/details/119214739)

条件变量和互斥锁同样也是一个结构,类型是pthread_cond_t类型。

初始化条件变量
pthread_cont_t cond;

//方式一:静态方式初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

//方式二:动态方式初始化(使用pthread_cond_init函数)
int pthread_cond_init(pthread_cond_t *restrict cond,
					  const pthread_condattr_t *restrict attr);
//参数1:需要初始化的条件变量
//参数2:条件变量的属性
条件变量的激发
//激发方式一:激发一个
int pthread_cond_signal(pthread_cond_t *cond);
//只激发等待在该条件变量上等待队列中的第一个线程

//激发方式二:激发所有
int pthread_cond_broadcast(pthread_cond_t *cond);
//激发所有等待在该条件变量上的线程
条件变量的等待
//等待方式一:无条件等待(条件不成了,会一直等待)
int pthread_cond_wait(pthread_cond_t *restrict cond,
            		  pthread_mutex_t *restrict mutex);
//参数1:等待的条件变量
//参数2:互斥锁,当条件满足后,需要互斥访问临界资源所以需要加锁

//等待方式二:计时等待
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
           				   pthread_mutex_t *restrict mutex,
          				   const struct timespec *restrict abstime);
//参数1:等待的条件变量
//参数2:互斥锁
//参数3:等待条件变量成立的最长时间,如果等待的时间到了,那么等待函数就返回,不会一直等待

条件变量的销毁

int pthread_cond_destroy(pthread_cond_t *cond);
代码演示
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

struct Data {
    int val;
    pthread_mutex_t lock;
    pthread_cond_t cond;
};

void *threadFunc(void *p)
{
    struct Data *pData = (struct Data *)p;

    //访问临界资源,需要相互访问
    pthread_mutex_lock(&pData->lock);

    //条件不满足,等待条件成立
    if(0 == pData->val){
        printf("条件不满足,等待条件满足\n");
        pthread_cond_wait(&pData->cond, &pData->lock);
        printf("条件成立,从条件变量上返回\n");
    }

    pthread_mutex_unlock(&pData->lock);

    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    struct Data data;
    memset(&data, 0, sizeof(data));

    data.val = 0;
    //锁和条件变量初始化
    pthread_mutex_init(&data.lock, NULL);
    pthread_cond_init(&data.cond, NULL);

    pthread_t thid;
    pthread_create(&thid, NULL, threadFunc, &data);

    //主线程让出时间片,让子线程先执行到pthread_cond_wait阻塞在条件变量上
    //然后主线程使用signal激活该子线程
    sleep(1);

    pthread_mutex_lock(&data.lock);
    
    //唤醒等待在条件变量上的线程
    pthread_cond_signal(&data.cond);
    printf("激发等待线程\n");

    pthread_mutex_unlock(&data.lock);

    pthread_join(thid, NULL);
    
    //锁和条件变量的销毁
    pthread_mutex_destroy(&data.lock);
    pthread_cond_destroy(&data.cond);

    return 0;
}

//运行结果:
条件不满足,等待条件满足
激发等待线程
条件成立,从条件变量上返回

上面是简单的条件变量的使用代码,看完代码后你因该是对这个代码有点疑惑才对,首先声明代码没有问题!想想看哪里有点疑惑?

疑惑点:首先应该放在锁上,子线程判断条件不满足,阻塞在pthread_cond_wait函数上,等待条件成立的信号;然后主线程sleep一秒之后,加锁,然后通知信号成立!想一下,子线程阻塞在pthread_cond_wait函数上之前是加锁了的,阻塞之后是没有解锁的,那么主线程是如何加锁成功的,并且调用了 pthread_cond_signal函数唤醒子线程的?

解惑:我们回头看一下pthread_cond_wait的原型

int pthread_cond_wait(pthread_cond_t *restrict cond,
            		  pthread_mutex_t *restrict mutex);

该函数的参数有一个条件变量,还有一个锁;条件变量很容易理解,那么这个锁呢?前面我讲原型的时候说了,为了访问临界资源需要加锁,那么我调用pthread_cond_wait函数前已经加锁了啊!那么我这个参数锁是干嘛的呢?其实pthread_cond_wait函数的源码实现中对该函数进行了功能划分(源码在glibc/nptl中可以查看),首先

  1. 第一步:加锁判断条件满足不满足,不满足调用pthread_cond_wait函数
  2. 第二步:由于在获取条件信息前加了锁,所以在pthread_cond_wait函数内部需要把锁释放,
  3. 第三步:睡眠
  4. 第四步:当收到条件满足的信号后,解除睡眠,
  5. 第五步:此时条件满足,说明资源可以使用,那么此时需要访问临界资源,所以需要加锁互斥访问临界资源!
  6. 第六步:函数返回!

通过我对pthread_cond_wait函数的分析你应该对我提出的问题有了全新的理解了!

pthread_cond_wait函数使用时需要的注意的是:该函数的锁参数,一定是你前面互斥加锁的时使用的锁变量,不然你咋在pthread_cond_wait函数内解锁呢!

本人能力有限,如有错误,望大佬不吝指出,原创不易,转载请注明出处!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值