我是靠谱客的博主 怕孤单翅膀,最近开发中收集的这篇文章主要介绍C++多线程学习07 unique_lock与scoped_lock,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、unique_lock唯一锁

lock_guard 最大的缺点是简单,没有给程序员提供足够的灵活度,因此,C++11 标准中定义了另外一个与 Mutex RAII 相关类 unique_lock,该类与 lock_guard 类相似,也很方便线程对互斥量上锁,但它提供了更好的上锁和解锁控制。

顾名思义,unique_lock 对象以独占所有权的方式( unique owership)管理 mutex 对象的上锁和解锁操作,所谓独占所有权,就是没有其他的 unique_lock 对象同时拥有某个 mutex 对象的所有权。

在构造(或移动(move)赋值)时,unique_lock 对象需要传递一个 Mutex 对象作为它的参数,新创建的 unique_lock 对象负责传入的 Mutex 对象的上锁和解锁操作。

std::unique_lock 对象也能保证在其自身析构时它所管理的 Mutex 对象能够被正确地解锁(即使没有显式地调用 unlock 函数)。因此,和 lock_guard 一样,这也是一种简单而又安全的上锁和解锁方式,尤其是在程序抛出异常后先前已被上锁的Mutex 对象可以正确进行解锁操作,极大地简化了程序员编写与 Mutex 相关的异常处理代码。

值得注意的是,unique_lock 对象同样也不负责管理 Mutex 对象的生命周期,unique_lock 对象只是简化了 Mutex 对象的上锁和解锁操作,方便线程对互斥量上锁,即在某个 unique_lock 对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而 unique_lock 的生命周期结束之后,它所管理的锁对象会被解锁,这一点和 lock_guard 类似,但 unique_lock 给程序员提供了更多的自由,我会在下面的内容中给大家介绍 unique_lock 的用法。
参考:https://zhangzc.blog.csdn.net/article/details/96852295?spm=1001.2101.3001.6650.7&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7-96852295-blog-51813140.pc_relevant_aa2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7-96852295-blog-51813140.pc_relevant_aa2&utm_relevant_index=9
先来看看unique_lock的定义:

template <class _Mutex>
class unique_lock { // whizzy class with destructor that unlocks mutex
public:
    using mutex_type = _Mutex;

    // CONSTRUCT, ASSIGN, AND DESTROY
    unique_lock() noexcept : _Pmtx(nullptr), _Owns(false) {}

    explicit unique_lock(_Mutex& _Mtx) : _Pmtx(_STD addressof(_Mtx)), _Owns(false) { // construct and lock
        _Pmtx->lock();
        _Owns = true;
    }

    unique_lock(_Mutex& _Mtx, adopt_lock_t)
        : _Pmtx(_STD addressof(_Mtx)), _Owns(true) { // construct and assume already locked
    }

    unique_lock(_Mutex& _Mtx, defer_lock_t) noexcept
        : _Pmtx(_STD addressof(_Mtx)), _Owns(false) { // construct but don't lock
    }

    unique_lock(_Mutex& _Mtx, try_to_lock_t)
        : _Pmtx(_STD addressof(_Mtx)), _Owns(_Pmtx->try_lock()) { // construct and try to lock
    }

补充一个关键字noexcept
noexcept形如其名地,表示其修饰的函数不会抛出异常。不过与throw()动态异常声明不同的是,在C++11中如果noexcept修饰的函数抛出了异常,编译器可以选择直接调用std::terminate()函数来终止程序的运行,这比基于异常机制的throw()在效率上会高一些。这是因为异常机制会带来一些额外开销,比如函数抛出异常,会导致函数栈被依次地展开(unwind),并依帧调用在本帧中已构造的自动变量的析构函数等。
unique_lock与lock_guard()一样是一个模板类,根据传进来的互斥量类型的不同生成不同种类的对象,其构造函数有以下几种:
01无参的
02只有互斥量的:此时与lock_guard一致,新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.lock() 对 Mutex 对象进行上锁,如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m,则当前线程将会被阻塞。
03除了互斥量还有adopt_lock的:已经拥有锁,不加锁而是收养已拥有的锁,出栈区会释放这个锁,_Owns(true)会将拥有设为true,导致在析构时会释放锁

~unique_lock() noexcept {
        if (_Owns) {
            _Pmtx->unlock();
        }
    }

04除了互斥量还有 defer_lock的 :新创建的 unique_lock 对象管理 Mutex 对象 m,但是在初始化的时候并不锁住 Mutex 对象,可以延后通过unique_lock来进行加锁。 m 应该是一个没有当前线程锁住的 Mutex 对象。_Owns(False)会将拥有设为false,导致在析构时不会解锁
05除了互斥量还有try_to_lock的:新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.try_lock() 对 Mutex 对象进行上锁,但如果上锁不成功,并不会阻塞当前线程。_Owns(_Pmtx->try_lock()),让mutex对象尝试去上锁,上锁成功的话 将_Owns设为true,失败的话设为false

class XMutex
{
public:
    XMutex(mutex& mux):mux_(mux)
    {
        cout << "Lock" << endl;
        mux.lock();
    }
    ~XMutex()
    {
        cout << "Unlock" << endl;
        mux_.unlock();
    }
private:
    mutex& mux_;
};

int main(int argc, char* argv[])
{

    {
        static mutex mux;
        {
            unique_lock<mutex> lock(mux);//与lock_guard效果一样
            lock.unlock();//lock_guard不能临时释放
            //临时释放锁
            lock.lock();
        }

        {
            //已经拥有锁 不锁定,退出栈区解锁
            mux.lock();
            unique_lock<mutex> lock(mux, adopt_lock);
        }
        {
            //延后加锁 不拥有 退出栈区不解锁
            unique_lock<mutex> lock(mux, defer_lock);
            //加锁 退出栈区解锁
            lock.lock();
        }
        {
            //mux.lock();
            //尝试加锁 不阻塞 失败不拥有锁
            unique_lock<mutex> lock(mux, try_to_lock);

            if (lock.owns_lock())
            {
                cout << "owns_lock" << endl;
            }
            else
            {
                cout << "not owns_lock" << endl;
            }
        }
    }
    getchar();
    return 0;
}

unique_lock lock(mux, try_to_lock);前mux已解锁地干干净净,所以try_to_lock上锁成功

二、scoped_lock范围锁

scoped_lock C++17 用于多个互斥体的免死锁 RAII 封装器 类似lock

最后

以上就是怕孤单翅膀为你收集整理的C++多线程学习07 unique_lock与scoped_lock的全部内容,希望文章能够帮你解决C++多线程学习07 unique_lock与scoped_lock所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部