zoukankan      html  css  js  c++  java
  • 读写锁的实现

    reference:
    原子操作、内存屏障、锁https://www.jianshu.com/p/1d90fe6627ad

    哪些操作本身是原子的?

    • 单核处理器下中断发生在指令之间,因此单指令操作都是原子的
    • 多核处理器下进行零次或一次对齐内存访问的汇编指令是原子的

    c++版读写锁 https://blog.csdn.net/zxc024000/article/details/88814461
    volatile
    谈谈C/C++中的volatile:https://zhuanlan.zhihu.com/p/33074506
    内存模型:https://cloud.tencent.com/developer/article/1479199

    • 易变性。所谓的易变性,在汇编层面反映出来,就是两条语句,下一条语句不会直接使用上一条语句对应的volatile变量的寄存器内容,而是重新从内存中读取。
    • 不可优化性。volatile告诉编译器,不要对变量进行各种激进的优化,甚至将变量直接消除,保证程序员写在代码中的指令,一定会被执行。
    • 顺序性。能够保证Volatile变量间的顺序性,编译器不会进行乱序优化。(但CPU依然可能会乱序,x86和amd只开启了 store-load ooo)

    volatile object - an object whose type is volatile-qualified, or a subobject of a volatile object, or a mutable subobject of a const-volatile object. Every access (read or write operation, member function call, etc.) made through a glvalue expression of volatile-qualified type is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access. This makes volatile objects suitable for communication with a signal handler, but not with another thread of execution, see std::memory_order). Any attempt to refer to a volatile object through a non-volatile glvalue (e.g. through a reference or pointer to non-volatile type) results in undefined behavior.

    C/C++ and "volatile"
    
    When writing single-threaded code, declaring a variable “volatile” can be very useful. The compiler will not omit or reorder accesses to volatile locations. Combine that with the sequential consistency provided by the hardware, and you’re guaranteed that the loads and stores will appear to happen in the expected order.
    
    However, accesses to volatile storage may be reordered with non-volatile accesses, so you have to be careful in multi-threaded uniprocessor environments (explicit compiler reorder barriers may be required). There are no atomicity guarantees, and no memory barrier provisions, so “volatile” doesn’t help you at all in multi-threaded SMP environments. The C and C++ language standards are being updated to address this with built-in atomic operations.
    
    If you think you need to declare something “volatile”, that is a strong indicator that you should be using one of the atomic operations instead. 
    

    Java版读写锁(来自打驰哥) https://www.cnblogs.com/DarrenChan/p/8619476.html
    防止写者饿死精要:
    写者到来的时候,先m_writeCount++,再判断是否读者为0,并且未出于写的过程中;(直接判断m_writeCount == 1是否可行?)
    读者到来的时候,先检查m_writeCount

    C++版本

    • RWLock.h
    #ifndef RWLOCK__H
    #define RWLOCK__H
    
    #ifndef __cplusplus
    #    error ERROR: This file requires C++ compilation(use a .cpp suffix)
    #endif
    
    #include <mutex>
    #include <condition_variable>
    
    namespace linduo {
    
    class RWLock {
     public:
        RWLock();
        virtual ~RWLock() = default;
    
        void lockWrite();
        void unlockWrite();
        void lockRead();
        void unlockRead();
    
     private:
        volatile int m_readCount;
        volatile int m_writeCount;
        volatile bool m_isWriting;
        std::mutex m_Lock;
        std::condition_variable m_readCond;
        std::condition_variable m_writeCond;
    };
    
    class ReadGuard {
     public:
        explicit ReadGuard(RWLock& lock);
        virtual ~ReadGuard();
    
     private:
        ReadGuard(const ReadGuard&);
        ReadGuard& operator=(const ReadGuard&);
    
     private:
        RWLock &m_lock;
    };
    
    
    class WriteGuard {
     public:
        explicit WriteGuard(RWLock& lock);
        virtual ~WriteGuard();
    
     private:
        WriteGuard(const WriteGuard&);
        WriteGuard& operator=(const WriteGuard&);
    
     private:
      RWLock& m_lock;
    };
    
    } /* namespace linduo */
    #endif  // RWLOCK__H
    
    • RWLock.cpp
    #include "RWLock.h"
    
    namespace linduo {
    
    RWLock::RWLock()
        : m_readCount(0)
        , m_writeCount(0)
        , m_isWriting(false) {
        }
    
    void RWLock::lockRead() {
        std::unique_lock<std::mutex> gurad(m_Lock);
        m_readCond.wait(gurad, [=] { return 0 == m_writeCount; });
        ++m_readCount;
    }
    
    void RWLock::unlockRead() {
        std::unique_lock<std::mutex> gurad(m_Lock);
        if (0 == (--m_readCount)
            && m_writeCount > 0) {
            // One write can go on
            m_writeCond.notify_one();
        }
    }
    
    void RWLock::lockWrite() {
        std::unique_lock<std::mutex> gurad(m_Lock);
        ++m_writeCount;
        m_writeCond.wait(gurad, [=] { return (0 == m_readCount) && !m_isWriting; });
        m_isWriting = true;
    }
    
    void RWLock::unlockWrite() {
        std::unique_lock<std::mutex> gurad(m_Lock);
        m_isWriting = false;
        if (0 == (--m_writeCount)) {
            // All read can go on
            m_readCond.notify_all();
        } else {
            // One write can go on
            m_writeCond.notify_one();
        }
    }
    
    ReadGuard::ReadGuard(RWLock &lock)
        : m_lock(lock) {
        m_lock.lockRead();
    }
    
    ReadGuard::~ReadGuard() {
        m_lock.unlockRead();
    }
    
    WriteGuard::WriteGuard(RWLock &lock)
        : m_lock(lock) {
        m_lock.lockWrite();
    }
    
    WriteGuard::~WriteGuard() {
        m_lock.unlockWrite();
    }
    
    } /* namespace linduo */
    
    • 使用
    RWLock m_Lock;
    
    void Wfunc() {
       // 写锁
       WriteGuard autoSync(m_Lock);
    }
    
    void Rfunc() {
      // 读锁
      ReadGuard autoSync(m_Lock);
    }
    
  • 相关阅读:
    枚举类
    泛型数组列表
    方法参数
    给一个数字和列表,判断列表中是否存在两个元素之和等于这个数字,并好之两个数的坐标
    selenium.common.exceptions.ElementNotVisibleException: Message: element not interactable报错
    python-selenium提供的execute_script调用js操作
    xlrd读取excel数据封装
    0531-练习题 os.system
    0528 文件操作习题
    05/17
  • 原文地址:https://www.cnblogs.com/dirge/p/11874856.html
Copyright © 2011-2022 走看看