IE盒子

搜索
查看: 92|回复: 0

C++ 互斥锁与条件变量

[复制链接]

4

主题

12

帖子

25

积分

新手上路

Rank: 1

积分
25
发表于 2023-3-29 01:57:37 | 显示全部楼层 |阅读模式
1 【定义】

互斥量:互斥锁是依赖互斥量实现的。互斥量可简单理解为仅有两种值true或false的信号量。
互斥锁:互斥锁基于互斥量实现,可用于共享数据访问的保护。即当线程访问共享数据时,
有如下动作:

  • 访问前,判断互斥锁是否已上锁(互斥量是否置为true)。若上锁,说明有其他线程再访问,当前线程阻塞直至互斥锁解锁;若未上锁,当前线程上锁,并访问共享数据。
  • 访问后,退出共享数据的访问,并解锁互斥锁。
在Linux C中互斥锁有pthread_mutex_t方法,但是对于C++编程中,更推荐使用lock_guard、unqiue_lock。主要有以下优势:

  • 无需考虑互斥量的初始化和销毁,在类的构造和析构函数中管理,无需使用者操心。
  • 采用RAII对互斥量进行了不同封装,提供了更方便的上锁机制。
2 【lock_guard与unique_lock】


  • lock_guard功能与std::mutex的lock与ublock功能相同。 不同的是,lock_guard析构时会自动解锁,使用时无须unlock。这就需要我们将共享资源的访问封装成尽可能小的函数,避免加锁时间过长。
  • 从构造与析构可以看出,lock_guard对象创建时会主动调用lock()加锁,销毁时会主动调用unlock()解锁。
<hr/>

  • unique_lock比lock_guard更加灵活,但性能不如lock_guard。unique_lock提供lock与unlock,同时析构时也会释放锁。
  • std::unique_lock 可以在构造时传递第二个参数用于管理互斥量,且能传递不同域中互斥量所有权。
  • std::unique_lock是可移动且不可拷贝的对象;
3 【cv条件变量】

mutex体现的是一种竞争,我离开了,通知你进来。
cond体现的是一种协作,我准备好了,通知你开始吧。
互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起配合使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其他的某个线程改变了条件变量,他将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线程间的同步。
两个线程操作同一临界区时,通过互斥锁保护,若A线程已经加锁,B线程再加锁时候会被阻塞,直到A释放锁,B再获得锁运行,进程B必须不停的主动获得锁、检查条件、释放锁、再获得锁、再检查、再释放,一直到满足运行的条件的时候才可以(而此过程中其他线程一直在等待该线程的结束),这种方式是比较消耗系统的资源的。而条件变量同样是阻塞,还需要通知才能唤醒,线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,该线程就休眠了,应该仍阻塞在这里,等待条件满足后被唤醒,节省了线程不断运行浪费的资源。这个过程一般用while语句实现。当线程B发现被锁定的变量不满足条件时会自动的释放锁并把自身置于等待状态,让出CPU的控制权给其它线程。其它线程 此时就有机会去进行操作,当修改完成后再通知那些由于条件不满足而陷入等待状态的线程。这是一种通知模型的同步方式,大大的节省了CPU的计算资源,减少了线程之间的竞争,而且提高了线程之间的系统工作的效率。这种同步方式就是条件变量。                                   
总而言之,为了避免因条件判断语句与其后的正文或wait语句之间的间隙而产生的漏判或误判,用一个mutex来保证。对于某个cond的判断,修改等操作某一时刻只有一个线程在访问。条件变量本身就是一个竞争资源,这个资源的作用是对其后程序正文的执行权,于是用一个锁来保护。
使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。



关于pthread_cond_wait()函数的解析

伪代码:



伪代码

//一段真实的代码:
                if (sample_info.related_sample_identity == write_params.sample_identity())
                {
                    {
                        std::unique_lock<std::mutex> lock(reception_mutex);
                        received_reply = true;
                        z = reply.z();
                    }
                    reception_cv.notify_one();
                }

//wait
if (request_writer_->write(static_cast<void*>(&request), listener_.write_params))
        {
            std::unique_lock<std::mutex> lock(listener_.reception_mutex);
            listener_.reception_cv.wait(lock, [&]()
                    {
                        return listener_.received_reply;
                    });
            z = listener_.z;
        }

【The End】

参考链接:C++并发编程 - 互斥锁(lock_guard和unique_lock)
条件变量为什么要和互斥锁一起使用_条件变量为什么要和锁一起用_一只牛_007的博客-CSDN博客
Linux服务器开发(线程控制)pthread_mutex_xxx(),和pthread_cond_xxx()实现线程同步功能_c语言pthread_mutex和pthread_cond系列函数进行同步_654654654654654的博客-CSDN博客
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表