• Linux | Linux使用互斥锁及条件变量替代信号量


    ========》Linux | Linux中的线程、互斥量、信号量的基本使用《========

    一、简述

    信号量是一个计数器,用于限制并发访问共享资源的线程数;此计数器始终介于 0 和信号量创建期间指定的最大值之间;
    - 当计数器严格大于0时,对Wait()的调用立即返回并递减计数器;
    - 一旦达到0,对Wait的任何后续调用都会阻塞,并且仅在信号量计数器再次变为严格正数时返回,因为调用Post()会增加计数器;
    
    通常,信号量可用于限制对共享资源的访问,该共享资源只能由某些固定数量的客户端同时访问;
    例如,在对酒店预订系统建模时,可以创建计数器等于可用房间总数的信号量。每次预留房间时,应通过调用Wait()获取信号量,每次释放房间时应通过调用Post释放信号量;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    C++11 和 Boost.Thread 都没有提供信号量:
    	信号量因太容易出错而被删除。通过互斥体和条件变量的组合可以更安全地实现相同的效果;Dijkstra(信号量的发明者)、
    	Hoare 和 Brinch Hansen 都贬低了信号量并提倡更结构化的替代方案。在 1969 年给 Brinch Hansen 的一封信中,Wirth 说“信号
    	量……不适合高级语言。” [Andrews-83] 将典型错误总结为“省略P或V ,或在一个信号量上不小心将P和V编码在另一个信号量
    	上”,忘记在临界区中包含对共享对象的所有引用,以及由于使用“条件同步和互斥”的相同原语;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    故以下我们将使用条件变量和互斥量来替代信号量
    
    • 1
    /** 封装条件变量 */
    class Cond {
    public:
        Cond();
        void wait(pthread_mutex_t mutex);
        void signal();
    
        ~Cond();
    
    private:
        pthread_cond_t m_cond;
    };
    
    /** 信号量封装使用条件变量和锁 */
    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;
    };
    
    
    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

    二、测试

    每个工作线程先等待信号量,然后输出线程 ID 和当前时间,输出操作以互斥锁同步以防止错位,睡眠一秒是为了模拟线程处理数
    据的耗时。
    
    • 1
    • 2
    sylar::OwnSemaphore g_sem(3);
    
    void Worker() {
        g_sem.wait();
    
        std::thread::id thread_id = std::this_thread::get_id();
    
        /* 获取时间 */
        struct tm tm;
        time_t t = time(0);
        localtime_r(&t, &tm);
        char buf[64];
        strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
        {
            sylar::Mutex::Lock lock(sylar::Mutex);
            std::cout << "Thread " << thread_id << ": wait succeeded" << " (" << buf << ")" << std::endl;
        }
        // Sleep 1 second to simulate data processing.
        std::this_thread::sleep_for(std::chrono::seconds(1));
    
        g_sem.notify();
    }
    
    
    int main() {
        const std::size_t SIZE = 3;
    
        std::vector<std::thread> v;
        v.reserve(SIZE);
    
        for (std::size_t i = 0; i < SIZE; ++i) {
            v.emplace_back(&Worker);
        }
    
        for (std::thread& t : v) {
            t.join();
        }
    
        return 0;
    }
    
    • 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

    测试结果
    在这里插入图片描述
    在这里插入图片描述

    参考文章
    https://segmentfault.com/a/1190000006818772

  • 相关阅读:
    ansible中waring处理方式
    .net core 和 WPF 开发升讯威在线客服系统:调用有道翻译接口实现实时自动翻译的方法
    趁热打铁,一起来看下Airtest1.2.7新增的那些断言API
    现代 PHP 新特性 —— 内置的 HTTP 服务器
    PostgreSQL 和 MySQL 在用途、好处、特性和特点上的异同
    Embarcadero Delphi 11,Delphi编写环境选项
    Android修行手册 - 一文全了解Kotlin几种静态变量、函数实现的那些事
    Java之—hutool工具类二维码生成跟背景图合并输出
    2022年武汉市仿制药一致性评价政策性奖励申报条件要求以及奖补措施!
    leetcode 583. 两个字符串的删除操作、72. 编辑距离
  • 原文地址:https://blog.csdn.net/weixin_45926547/article/details/126100580