【Linux】线程同步

2024-03-19 5645阅读

线程同步

  • 一、条件变量
    • 1. 同步概念
    • 2. 条件变量概念
    • 3. 条件变量接口
      • (1)pthread_cond_init()
      • (2)pthread_cond_destroy()
      • (3)pthread_cond_wait()
      • (4)pthread_cond_signal()
      • (5)pthread_cond_broadcast()
      • (6)使用接口
      • 二、生产者消费者模式
        • 1. 概念
        • 2. 生产者消费者模式优点
        • 3. 基于 BlockingQueue 的生产者消费者模型
        • 三、POSIX 信号量
          • 1. 回顾信号量
          • 2. POSIX 信号量接口
            • (1)sem_init()
            • (2)sem_destroy()
            • (3)sem_wait()
            • (4)sem_post()
            • 3. 基于环形队列的生产消费模型
              • (1)环形队列
              • (2)原理
              • (3)代码实现
              • 四、线程池
              • 五、其他常见的锁
              • 六、读者写者问题
                • 1. 读写锁
                • 2. 读写锁

                  一、条件变量

                  1. 同步概念

                  同步问题是保证数据安全的情况下,让线程访问资源具有一定的顺序性,从而有效避免饥饿问题,叫做同步。

                  2. 条件变量概念

                  所以怎么才能让线程按照一定的顺序去访问资源呢?也就是同步的解决方案是什么呢?这个解决方案在 Linux 中称为条件变量。

                  什么叫做条件变量呢?以前我们使用的纯加锁的时候,没有申请到加锁的线程,就直接阻塞挂起了,这个场景为纯互斥场景,也就是线程没有顺序地执行的,谁能申请到锁谁就能得到资源。而条件变量就是可以做到让线程在一个等待队列中按照顺序等待,按照它们到来的先后顺序进入队列等待,前提是这些线程都是申请锁失败的,因为是要保证资源安全的情况下。而且,在资源就绪的时候,也就是有线程释放锁后,这个条件变量还需要提供一种通知机制,唤醒一个或者全部队列中的线程,让队头的线程去访问资源。这就是条件变量。

                  例如一个线程访问队列时,该队列为共享资源,发现队列为空,它只能等待,直到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量。

                  3. 条件变量接口

                  (1)pthread_cond_init()

                  初始化条件变量的接口:

                  				int pthread_cond_init(pthread_cond_t *restrict cond,
                  				              const pthread_condattr_t *restrict attr);
                  

                  其中第一个参数类型,也是 pthread 库给我们提供的数据类型,我们先要定义一个这样类型的条件变量,也就是要初始化的条件变量。第二个参数是属性,我们设为空即可。

                  条件变量的初始化和互斥锁的初始化类似,也可以定义一个全局的条件变量,用法也一样,全局或静态的条件变量可以不用初始化和释放。定义全局的条件变量如下:

                  				pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
                  

                  (2)pthread_cond_destroy()

                  释放条件变量:

                  				int pthread_cond_destroy(pthread_cond_t *cond);
                  

                  (3)pthread_cond_wait()

                  申请锁失败或者等待条件满足时,加入等待队列中:

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

                  第一个参数就是我们初始化的条件变量;第二个参数是一把锁,我们后面再介绍。

                  (4)pthread_cond_signal()

                  唤醒一个线程的接口:

                  				int pthread_cond_signal(pthread_cond_t *cond);
                  

                  (5)pthread_cond_broadcast()

                  唤醒所有线程:

                  				int pthread_cond_broadcast(pthread_cond_t *cond);
                  

                  【Linux】线程同步 第1张

                  (6)使用接口

                  下面我们将上面的接口和互斥接口一起使用起来。我们知道,当多个线程向显示器上打印时,其实就是多个线程访问同一个共享资源,此时如果不加锁,打印出来的信息就是乱的。现在我们就模拟这个场景,对显示器这个共享资源加锁,并添加条件变量实现同步。

                  				pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
                  				pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
                  				
                  				int cnt = 0;
                  				
                  				void* func(void* args)
                  				{
                  				    pthread_detach(pthread_self());
                  				    uint64_t i = (uint64_t)args;
                  				
                  				    while(1)
                  				    {
                  				        pthread_mutex_lock(&lock);
                  				
                  				        // pthread_cond_wait 让线程加入等待队列的时候,会自动释放锁
                  				        pthread_cond_wait(&cond, &lock);       
                  				        cout 

    免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

    目录[+]