读写锁及其实现

适用场景
少量写+大量的读
注意这个是先是读优先的
读写锁的三种状态
1.读模式下的加锁
2.写模式下的加锁
3.不加锁
加锁规则
写的情况:
1.一次只有一个线程可以占用写模式的读写锁
2.一个执行流在写的时候,其他执行流既不能写,也不能读,只能陷入阻塞状态
3.多个读取线程可以同时占用读模式下的读写锁,在读写锁的内部有一个引用计数器
引用计数:标识着有多少以读模式打开的读写锁线程
1.每当一个线程以读模式打开读写锁的时候,引用计数器+1
2.当一个线程释放以读模式打开读写锁的时候,引用计数器-1
作用:判断释放读模式打开的读写锁时,能否完全解锁
1.如果引用计数器完全减为0,表示当前没有读模式的线程占用读写锁,那么以读模式的读写锁就解锁了
2.引用计数器大于0,表明还有线程以读模式打开读写锁,就会和想要以写模式打开的读写锁进行互斥

当前锁的状态 读锁请求 写锁请求
无锁 可以 可以
读锁 可以 阻塞
写锁 阻塞 阻塞

写独占,都共享,读锁优先级高

操作接口
定义

pthread_rwlock_t

初始化

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);

attr共有三种选择
1.PTHREAD_RWLOCK_PREFER_READER_NP (默认设置) 读者优先,可能会导致写者饥饿情况
2.PTHREAD_RWLOCK_PREFER_WRITER_NP 写者优先,目前有 BUG,导致表现行为和 PTHREAD_RWLOCK_PREFER_READER_NP 一致
3.PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 写者优先,但写者不能递归加锁
加锁
以读模式打开,进行加锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

以写模式打开,进行加锁

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

解锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

销毁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

完整代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using std::cout;
using std::vector;
using std::string;
using std::endl;

volatile int ticket = 1000;//保持变量ticket对内存可见性,防止编译器过度优化
pthread_rwlock_t rwlock;	//定义全局的读写锁变量
//给线程进行标号的结构体
struct ThreadAttr {
    pthread_t tid;
    size_t id;
};

//初始化读写锁
void init_rwlock(int state) {
    //write priority
    if(state == 0) {
        pthread_rwlockattr_t attr;
        pthread_rwlockattr_init(&attr);
        //定义attr变量为 写优先,但是写的时候不能递归加锁
        pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
        pthread_rwlock_init(&rwlock,&attr);
        pthread_rwlockattr_destroy(&attr);
    }
    else { //read priority  && write hunger
        pthread_rwlock_init(&rwlock,nullptr);
    }
}

void join_threads(vector<ThreadAttr>& vec) {
    for(auto& eoch : vec) {
        pthread_join(eoch.tid,nullptr);
    }
}

void* readStart(void* arg)
{
    ThreadAttr* info = (ThreadAttr*)arg;
    while(1) {
        pthread_rwlock_rdlock(&rwlock);
        if(ticket <= 0) {
            pthread_rwlock_unlock(&rwlock);
            break;
        }
        cout<<"thread reader: "<<info->id<<" : "<<ticket<<endl;
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }
    return nullptr;
}

void* writeStart(void* arg)
{
    ThreadAttr* info = (ThreadAttr*) arg;
    while(1) {
        pthread_rwlock_wrlock(&rwlock);
        if(ticket <= 0) {
            pthread_rwlock_unlock(&rwlock);
            break;
        }
        cout<<"thread write "<<info->id<<" : "<<--ticket<<endl;
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }
    return nullptr;
}

int main() {
    const size_t reader_nr = 2;
    const size_t writer_nr = 1000;

    vector<ThreadAttr> readers(reader_nr); 
    vector<ThreadAttr> writers(writer_nr);

    init_rwlock(0);//0-->read priority 1--> write priority
    for(size_t i = 0; i < readers.size(); i++) {
        readers[i].id = i;
        pthread_create(&readers[i].tid,nullptr,readStart,(void*)&readers[i]);
    }

    for(size_t i = 0; i < writers.size(); i++) {
        writers[i].id = i;
        pthread_create(&writers[i].tid,nullptr,writeStart,(void*)&writers[i]);
    }

    //thread wait 
    join_threads(writers);
    join_threads(readers);

    pthread_rwlock_destroy(&rwlock);
    return 0;
}

使用C++11实现读写锁
使用互斥锁和条件变量实现读写锁

class readwrite_lock  
{  
public:  
    readwrite_lock()  
        : stat(0)  
    {  
    }  
  
    void readLock()  
    {  
        mtx.lock();  
        while (stat < 0)  
            cond.wait(mtx);  
        ++stat;  
        mtx.unlock();  
    }  
  
    void readUnlock()  
    {  
        mtx.lock();  
        if (--stat == 0)  
            cond.notify_one(); // 叫醒一个等待的写操作  
        mtx.unlock();  
    }  
  
    void writeLock()  
    {  
        mtx.lock();  
        while (stat != 0)  
            cond.wait(mtx);  
        stat = -1;  
        mtx.unlock();  
    }  
  
    void writeUnlock()  
    {  
        mtx.lock();  
        stat = 0;  
        cond.notify_all(); // 叫醒所有等待的读和写操作  
        mtx.unlock();  
    }  
  
private:  
    mutex mtx;  
    condition_variable cond;  
    int stat; // == 0 无锁;> 0 已加读锁个数;< 0 已加写锁  
};  

用mutex和condtion实现写优先的读写锁

class RWLock {  
private:  
    pthread_mutex_t mxt;  
    pthread_cond_t cond;  
    int rd_cnt;//等待读的数量  
    int wr_cnt;//等待写的数量  
  
public:  
    RWLock() :rd_cnt(0), wr_cnt(0) {  
        pthread_mutex_init(&mxt,NULL);  
        pthread_cond_init(&cond,NULL);  
    }  
  
    void readLock() {  
        pthread_mutex_lock(&mxt);  
  
        ++rd_cnt;  
        while(wr_cnt > 0)  
            pthread_mutex_wait(&cond, &mxt);  
          
        pthread_mutex_unlock(&mxt);  
    }  
  
    void readUnlock() {  
        pthread_mutex_lock(&mxt);  
          
        --rd_cnt;  
        if (rd_cnt == 0 )  
            pthread_cond_signal(&cond);  
  
        pthread_mutex_unlock(&mxt);  
    }  
  
    void writeLock() {  
        pthread_mutex_lock(&mxt);  
  
        ++wr_cnt;  
        while (wr_cnt + rd_cnt >=2)  
            pthread_cond_wait(&cond, &mxt);  
  
        pthread_mutex_unlock(&mxt);  
    }  
  
    void writerUnlock() {  
        pthread_mutex_lock(&mxt);  
  
        --wr_cnt;  
        if(wr_cnt==0)  
            pthread_cond_signal(&cond);  
  
        pthread_mutex_unlock(&mxt);  
    }  
}; 

你可能感兴趣的:(C++并发,c++)