• 【C++模块实现】| 【07】对于互斥、自旋锁、条件变量、信号量简介及封装


    ========》以下全部代码查看《========

    索引

    【C++模块实现】| 【01】日志系统实现
    【C++模块实现】| 【02】日志系统优化
    【C++模块实现】| 【03】文件管理模块
    【C++模块实现】| 【04】配置模块
    【C++模块实现】| 【05】日志模块增加配置模块的功能
    【C++模块实现】| 【06】日志模块添加循环覆盖写文件功能

    该模块是从sylar服务器框架中学习的,以下将会对其进行总结以加深对该框架的理解;
    
    • 1

    ========》视频地址《========

    一、简介

    ========》互斥量、信号量、条件变量的基本使用及参考代码《=======

    以下对锁的封装能够使用类的构造函数来加锁,析构函数进行释放锁;
    sylar::Mutex s_mutes;
    
    {
    	sylar::Mutex::Lock lock(s_mutes);	// 加锁操作
    	...
    	// 当离开该作用域时,该lock会被回收,由于它时自动变量,此时即调用析构函数,执行是方法锁的操作;
    	// 该方法简化了锁的使用方法,不需要手动释放锁,避免出现死锁的现象;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    1.1 互斥锁

    互斥锁Mutex是一种用于多线程编程中,防止两条线程同时对同一公共资源进行读写的机制;
    	- 该目的通过将代码切片成一个一个的临界区域(critical section)达成;
    	- 临界区域指的是一块对公共资源进行存取的代码,并非一种机制或是算法;
    	- 一个程序、进程、线程可以拥有多个临界区域,但是并不一定会应用互斥锁。
    flag、队列、计数器、中断处理程序等用于在多条并行运行的代码间传递数据、同步状态等的资源。维护这些资源的同步、一致和完
    整是很困难的,因为一条线程可能在任何一个时刻被暂停(休眠)或者恢复(唤醒);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    // 声明一个互斥量    
    pthread_mutex_t mtx;
    // 初始化 
    pthread_mutex_init(&mtx, NULL);
    // 加锁  
    pthread_mutex_lock(&mtx);
    // 解锁 
    pthread_mutex_unlock(&mtx);
    // 销毁
    pthread_mutex_destroy(&mtx);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    /**
     * @brief 互斥量
     */
    class Mutex : Noncopyable {
    public: 
        /// 局部锁
        typedef ScopedLockImpl<Mutex> Lock;
    
        /**
         * @brief 构造函数
         */
        Mutex() {
            pthread_mutex_init(&m_mutex, nullptr);
        }
    
        /**
         * @brief 析构函数
         */
        ~Mutex() {
            pthread_mutex_destroy(&m_mutex);
        }
    
        /**
         * @brief 加锁
         */
        void lock() {
            pthread_mutex_lock(&m_mutex);
        }
    
        /**
         * @brief 解锁
         */
        void unlock() {
            pthread_mutex_unlock(&m_mutex);
        }
    
        pthread_mutex_t getMutex() const { return m_mutex; }
    private:
        /// mutex
        pthread_mutex_t m_mutex;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    1.2 读写锁

    读写锁是计算机程序的并发控制的一种同步机制,用于解决读写问题。读操作可并发重入,写操作是互斥的;
    	- 读写锁通常用互斥锁、条件变量、信号量实现;
    
    
    【读写锁可以有不同的操作模式优先级】
    	- 读操作优先:允许最大并发,但写操作可能饿死;
    	- 写操作优先:一旦所有已经开始的读操作完成,等待的写操作立即获得锁。内部实现需要两把互斥锁;
    	- 未指定优先级
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    /**
     * @brief 读写互斥量
     */
    class RWMutex : Noncopyable{
    public:
    
        /// 局部读锁
        typedef ReadScopedLockImpl<RWMutex> ReadLock;
    
        /// 局部写锁
        typedef WriteScopedLockImpl<RWMutex> WriteLock;
    
        /**
         * @brief 构造函数
         */
        RWMutex() {
            pthread_rwlock_init(&m_lock, nullptr);
        }
        
        /**
         * @brief 析构函数
         */
        ~RWMutex() {
            pthread_rwlock_destroy(&m_lock);
        }
    
        /**
         * @brief 上读锁
         */
        void rdlock() {
            pthread_rwlock_rdlock(&m_lock);
        }
    
        /**
         * @brief 上写锁
         */
        void wrlock() {
            pthread_rwlock_wrlock(&m_lock);
        }
    
        /**
         * @brief 解锁
         */
        void unlock() {
            pthread_rwlock_unlock(&m_lock);
        }
    
    private:
        /// 读写锁
        pthread_rwlock_t m_lock;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    1.3 自旋锁

    自旋锁是计算机科学用于多线程同步的一种锁,线程反复检查锁变量是否可用。由于线程在这一过程中保持执行,因此是一种忙等
    待。一旦获取了自旋锁,线程会一直保持该锁,直至显式释放自旋锁;
    
    - 自旋锁避免了进程上下文的调度开销,因此对于线程只会阻塞很短时间的场合是有效的;
    - 自旋锁用于处理器之间的互斥,适合保护很短的临界区,并且不允许在临界区睡眠。申请自旋锁的时候,如果自旋锁被其他处理器
    	占有,本处理器自旋等待(也称为忙等待);因此操作系统的实现在很多地方往往用自旋锁;
    - 单核CPU不适于使用自旋锁,这里的单核CPU指的是单核单线程的CPU,因为,在同一时间只有一个线程是处在运行状态,假设
    	运行线程A发现无法获取锁,只能等待解锁,但因为A自身不挂起,所以那个持有锁的线程B没有办法进入运行状态,只能等到操
    	作系统分给A的时间片用完,才能有机会被调度。这种情况下使用自旋锁的代价很高;
    
    获取、释放自旋锁,实际上是读写自旋锁的存储内存或寄存器。因此这种读写操作必须是原子的;
    通常用test-and-set等原子操作来实现;
    
    【优点】:
    	- 自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上
    	下文切换,执行速度快。
    	- 非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入内核态,当获取到锁的时候需要从内核态恢复,需要线程上下文切换。
    	(线程被阻塞后便进入内核(Linux)调度状态,这个会导致系统在用户态与内核态之间来回切换,严重影响锁的性能)。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    /**
     * @brief 自旋锁
     */
    class Spinlock : Noncopyable {
    public:
        /// 局部锁
        typedef ScopedLockImpl<Spinlock> Lock;
    
        /**
         * @brief 构造函数
         */
        Spinlock() {
            pthread_spin_init(&m_mutex, 0);
        }
    
        /**
         * @brief 析构函数
         */
        ~Spinlock() {
            pthread_spin_destroy(&m_mutex);
        }
    
        /**
         * @brief 上锁
         */
        void lock() {
            pthread_spin_lock(&m_mutex);
        }
    
        /**
         * @brief 解锁
         */
        void unlock() {
            pthread_spin_unlock(&m_mutex);
        }
    private:
        /// 自旋锁
        pthread_spinlock_t m_mutex;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    1.4 局部锁

    /**
     * @brief 局部锁的模板实现
     */
    template<class T>
    struct ScopedLockImpl {
    public:
        /**
         * @brief 构造函数
         * @param[in] mutex Mutex
         */
        ScopedLockImpl(T& mutex)
            :m_mutex(mutex) {
            m_mutex.lock();
            m_locked = true;
        }
    
        /**
         * @brief 析构函数,自动释放锁
         */
        ~ScopedLockImpl() {
            unlock();
        }
    
        /**
         * @brief 加锁
         */
        void lock() {
            if(!m_locked) {
                m_mutex.lock();
                m_locked = true;
            }
        }
    
        /**
         * @brief 解锁
         */
        void unlock() {
            if(m_locked) {
                m_mutex.unlock();
                m_locked = false;
            }
        }
    private:
        /// mutex
        T& m_mutex;
        /// 是否已上锁
        bool m_locked;
    };
    
    /**
     * @brief 局部读锁模板实现
     */
    template<class T>
    struct ReadScopedLockImpl {
    public:
        /**
         * @brief 构造函数
         * @param[in] mutex 读写锁
         */
        ReadScopedLockImpl(T& mutex)
            :m_mutex(mutex) {
            m_mutex.rdlock();
            m_locked = true;
        }
    
        /**
         * @brief 析构函数,自动释放锁
         */
        ~ReadScopedLockImpl() {
            unlock();
        }
    
        /**
         * @brief 上读锁
         */
        void lock() {
            if(!m_locked) {
                m_mutex.rdlock();
                m_locked = true;
            }
        }
    
        /**
         * @brief 释放锁
         */
        void unlock() {
            if(m_locked) {
                m_mutex.unlock();
                m_locked = false;
            }
        }
    private:
        /// mutex
        T& m_mutex;
        /// 是否已上锁
        bool m_locked;
    };
    
    /**
     * @brief 局部写锁模板实现
     */
    template<class T>
    struct WriteScopedLockImpl {
    public:
        /**
         * @brief 构造函数
         * @param[in] mutex 读写锁
         */
        WriteScopedLockImpl(T& mutex)
            :m_mutex(mutex) {
            m_mutex.wrlock();
            m_locked = true;
        }
    
        /**
         * @brief 析构函数
         */
        ~WriteScopedLockImpl() {
            unlock();
        }
    
        /**
         * @brief 上写锁
         */
        void lock() {
            if(!m_locked) {
                m_mutex.wrlock();
                m_locked = true;
            }
        }
    
        /**
         * @brief 解锁
         */
        void unlock() {
            if(m_locked) {
                m_mutex.unlock();
                m_locked = false;
            }
        }
    private:
        /// Mutex
        T& m_mutex;
        /// 是否已上锁
        bool m_locked;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146

    1.5 信号量

    ========》使用互斥锁及条件变量替代信号量《========

    /**
     * @brief 信号量
     */
    class Semaphore : Noncopyable {
    public:
        /**
         * @brief 构造函数
         * @param[in] count 信号量值的大小
         */
        Semaphore(uint32_t count = 0);
    
        /**
         * @brief 析构函数
         */
        ~Semaphore();
    
        /**
         * @brief 获取信号量
         */
        void wait();
    
        /**
         * @brief 释放信号量
         */
        void notify();
    private:
        sem_t m_semaphore;
    };
    
    /** 信号量封装使用条件变量和锁 */
    class OwnSemaphore : Noncopyable {
    public:
        typedef Mutex MutexType;
        OwnSemaphore(size_t count=0);
        ~OwnSemaphore();
    
        void wait();
        void notify();
    
        size_t getCount() const { return m_count; }
        void reset() { m_count = 0;}
    
    private:
        size_t m_count;
        MutexType m_mutex;
        Cond m_cond;
    };
    
    Semaphore::Semaphore(uint32_t count) {
        if(sem_init(&m_semaphore, 0, count)) {
            throw std::logic_error("sem_init error");
        }
    }
    
    Semaphore::~Semaphore() {
        sem_destroy(&m_semaphore);
    }
    
    void Semaphore::wait() {
        if(sem_wait(&m_semaphore)) {
            throw std::logic_error("sem_wait error");
        }
    }
    
    void Semaphore::notify() {
        if(sem_post(&m_semaphore)) {
            throw std::logic_error("sem_post error");
        }
    }
    
    OwnSemaphore::OwnSemaphore(size_t count)
        :m_count(count){
    }
    
    OwnSemaphore::~OwnSemaphore() {
    }
    
    void OwnSemaphore::wait() {
        MutexType::Lock lock(m_mutex);
        while (m_count == 0) {
            m_cond.wait(m_mutex.getMutex());
        }
        --m_count;
    }
    
    void OwnSemaphore::notify() {
        m_count++;
        m_cond.signal();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    1.6 条件变量

    /** 封装条件变量 */
    class Cond {
    public:
        Cond();
        void wait(pthread_mutex_t mutex);
        void signal();
    
        ~Cond();
    
    private:
        pthread_cond_t m_cond;
    };
    
    Cond::Cond() {
        pthread_cond_init(&m_cond, NULL);
    }
    
    void Cond::wait(pthread_mutex_t mutex) {
        pthread_cond_wait(&m_cond, &mutex);
    }
    
    void Cond::signal() {
        pthread_cond_signal(&m_cond);
    }
    
    Cond::~Cond() {
        pthread_cond_destroy(&m_cond);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    1.8 原子操作及原子锁

    =======》原子类型与原子操作《=======

    /**
     * @brief 原子锁
     */
    class CASLock : Noncopyable {
    public:
        /// 局部锁
        typedef ScopedLockImpl<CASLock> Lock;
    
        /**
         * @brief 构造函数
         */
        CASLock() {
            m_mutex.clear();
        }
    
        /**
         * @brief 析构函数
         */
        ~CASLock() {
        }
    
        /**
         * @brief 上锁
         */
        void lock() {
            while(std::atomic_flag_test_and_set_explicit(&m_mutex, std::memory_order_acquire));
        }
    
        /**
         * @brief 解锁
         */
        void unlock() {
            std::atomic_flag_clear_explicit(&m_mutex, std::memory_order_release);
        }
    private:
        /// 原子状态
        volatile std::atomic_flag m_mutex;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
  • 相关阅读:
    基于某钉探索针对CEF框架的一些逆向思路
    项目会议如何开
    腾讯云对象存储
    [MT8766][Android12] 增加应用安装白名单或者黑名单
    利用C++开发一个迷你的英文单词录入和测试小程序-升级版本
    26对称矩阵及正定性
    2023.10.21 关于 阻塞队列
    关于QGC Landing Pattern规划的计算过程
    Java面向对象,全程无废话,偏实战
    查询三级数据结构sql语句
  • 原文地址:https://blog.csdn.net/weixin_45926547/article/details/126101676