c++11实现写优先的读写锁

先直接贴出代码:

#ifndef __WRITE_FIRST_RW_LOCK_H
#define __WRITE_FIRST_RW_LOCK_H
 
#include <mutex>
#include <condition_variable>
 
class WfirstRWLock
{
public:
	WfirstRWLock() = default;
	~WfirstRWLock() = default;
public:
	void lock_read()
	{
		std::unique_lock<std::mutex> ulk(counter_mutex);
		cond_r.wait(ulk, [=]()->bool {return write_cnt == 0; });
		++read_cnt;
	}
	void lock_write()
	{
		std::unique_lock<std::mutex> ulk(counter_mutex);
		++write_cnt;
		cond_w.wait(ulk, [=]()->bool {return read_cnt == 0 && !inwriteflag; });
		inwriteflag = true;
	}
	void release_read()
	{
		std::unique_lock<std::mutex> ulk(counter_mutex);
		if (--read_cnt == 0 && write_cnt > 0)
		{
			cond_w.notify_one();
		}
	}
	void release_write()
	{
		std::unique_lock<std::mutex> ulk(counter_mutex);
		if (--write_cnt == 0)
		{
			cond_r.notify_all();
		}
		else
		{
			cond_w.notify_one();
		}
		inwriteflag = false;
	}
	
private:
	volatile size_t read_cnt{ 0 };
	volatile size_t write_cnt{ 0 };
	volatile bool inwriteflag{ false };
	std::mutex counter_mutex;
	std::condition_variable cond_w;
	std::condition_variable cond_r;
};
 
template <typename _RWLockable>
class unique_writeguard
{
public:
	explicit unique_writeguard(_RWLockable &rw_lockable)
		: rw_lockable_(rw_lockable)
	{
		rw_lockable_.lock_write();
	}
	~unique_writeguard()
	{
		rw_lockable_.release_write();
	}
private:
	unique_writeguard() = delete;
	unique_writeguard(const unique_writeguard&) = delete;
	unique_writeguard& operator=(const unique_writeguard&) = delete;
private:
	_RWLockable &rw_lockable_;
};
template <typename _RWLockable>
class unique_readguard
{
public:
	explicit unique_readguard(_RWLockable &rw_lockable)
		: rw_lockable_(rw_lockable)
	{
		rw_lockable_.lock_read();
	}
	~unique_readguard()
	{
		rw_lockable_.release_read();
	}
private:
	unique_readguard() = delete;
	unique_readguard(const unique_readguard&) = delete;
	unique_readguard& operator=(const unique_readguard&) = delete;
private:
	_RWLockable &rw_lockable_;
};
 
#endif

可以看出用c++11实现读写锁变得非常简洁,在读取量非常大且写入频率很低的时候,通过一个简单的写入线程计数可以避免大量的 cond_w.notify_one();减少读取线程因此发生的切换。 这里需要注意的是对写操作加锁时是先增加写线程计数再判断条件并等待,释放写锁时减少写线程计数并判断是否还有写操作等待,如果有只能唤醒一个写等待。另外,直接使用lock、unlock在c++中是不推荐的,推荐采用RAII方法,即类unique_writeguard,unique_readguard。

此外,C++ 17 中提供了std::shared_mutex,可以实现了读写锁的功能。
libgo功能co_rwmutext.h中也实现了读写锁,性能比上述的还要好。libgo源码

#pragma once
#include "../common/config.h"
#include "../scheduler/processer.h"
#include <queue>
#include "co_condition_variable.h"

namespace co
{

/// 读写锁
class CoRWMutex
{
    LFLock lock_;
    long lockState_;  // 0:无锁, >=1:读锁, -1:写锁

    // 兼容原生线程
    ConditionVariableAny rCv_;
    ConditionVariableAny wCv_;

    // 是否写优先
    bool writePriority_;

public:
    explicit CoRWMutex(bool writePriority = true);
    ~CoRWMutex();

    void RLock();
    bool RTryLock();
    void RUnlock();

    void WLock();
    bool WTryLock();
    void WUnlock();

    bool IsLock();

private:
    void TryWakeUp();

public:
    class ReadView
    {
        friend class CoRWMutex;
        CoRWMutex * self_;

    public:
        void lock();
        bool try_lock();
        bool is_lock();
        void unlock();

        ReadView() = default;
        ReadView(ReadView const&) = delete;
        ReadView& operator=(ReadView const&) = delete;
    };

    class WriteView
    {
        friend class CoRWMutex;
        CoRWMutex * self_;

    public:
        void lock();
        bool try_lock();
        bool is_lock();
        void unlock();

        WriteView() = default;
        WriteView(WriteView const&) = delete;
        WriteView& operator=(WriteView const&) = delete;
    };

    ReadView& Reader();
    WriteView& Writer();

    // 兼容旧版接口
    ReadView& reader();
    WriteView& writer();

private:
    ReadView readView_;
    WriteView writeView_;
};

typedef CoRWMutex co_rwmutex;
typedef CoRWMutex::ReadView co_rmutex;
typedef CoRWMutex::WriteView co_wmutex;

} //namespace co

#include "co_rwmutex.h"
#include "../scheduler/scheduler.h"

namespace co
{

CoRWMutex::CoRWMutex(bool writePriority)
{
    lockState_ = 0;
    writePriority_ = writePriority;
    readView_.self_ = writeView_.self_ = this;
}
CoRWMutex::~CoRWMutex()
{
    assert(lock_.try_lock());
    assert(lockState_ == 0);
    readView_.self_ = writeView_.self_ = nullptr;
}

void CoRWMutex::RLock()
{
    std::unique_lock<LFLock> lock(lock_);

retry:
    if (writePriority_) {
        // 写优先
        if (lockState_ >= 0 && wCv_.empty()) {
            ++lockState_;
            return ;
        }
    } else {
        // 读优先
        if (lockState_ >= 0) {
            ++lockState_;
            return ;
        }
    }

    rCv_.wait(lock);
    goto retry;
}
bool CoRWMutex::RTryLock()
{
    std::unique_lock<LFLock> lock(lock_);
    if (lockState_ >= 0) {
        ++lockState_;
        return true;
    }
    return false;
}
void CoRWMutex::RUnlock()
{
    std::unique_lock<LFLock> lock(lock_);
    assert(lockState_ > 0);
    if (--lockState_ > 0)
        return ;

    TryWakeUp();
}

void CoRWMutex::WLock()
{
    std::unique_lock<LFLock> lock(lock_);

retry:
    if (lockState_ == 0) {
        lockState_ = -1;
        return ;
    }

    wCv_.wait(lock);
    goto retry;
}
bool CoRWMutex::WTryLock()
{
    std::unique_lock<LFLock> lock(lock_);
    if (lockState_ == 0) {
        lockState_ = -1;
        return true;
    }
    return false;
}
void CoRWMutex::WUnlock()
{
    std::unique_lock<LFLock> lock(lock_);
    assert(lockState_ == -1);

    lockState_ = 0;
    TryWakeUp();
}

void CoRWMutex::TryWakeUp()
{
    // 优先唤醒写等待
    if (wCv_.notify_one())
        return ;

    // 唤醒读等待
    rCv_.notify_all();
}

bool CoRWMutex::IsLock()
{
    std::unique_lock<LFLock> lock(lock_);
    return lockState_ == -1;
}

CoRWMutex::ReadView & CoRWMutex::Reader()
{
    return readView_;
}
CoRWMutex::WriteView & CoRWMutex::Writer()
{
    return writeView_;
}
CoRWMutex::ReadView & CoRWMutex::reader()
{
    return readView_;
}
CoRWMutex::WriteView & CoRWMutex::writer()
{
    return writeView_;
}

void CoRWMutex::ReadView::lock()
{
    self_->RLock();
}
bool CoRWMutex::ReadView::try_lock()
{
    return self_->RTryLock();
}
bool CoRWMutex::ReadView::is_lock()
{
    return self_->IsLock();
}
void CoRWMutex::ReadView::unlock()
{
    return self_->RUnlock();
}

void CoRWMutex::WriteView::lock()
{
    self_->WLock();
}
bool CoRWMutex::WriteView::try_lock()
{
    return self_->WTryLock();
}
bool CoRWMutex::WriteView::is_lock()
{
    return self_->IsLock();
}
void CoRWMutex::WriteView::unlock()
{
    self_->WUnlock();
}

} //namespace co

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C11标准库中提供了读写锁,可以用来实现多个线程对同一资源的并发读操作。下面是使用读写锁的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <threads.h> int data = 0; rwlock_t lock; int reader(void* arg) { int id = *(int*)arg; while (1) { thrd_sleep((struct timespec){.tv_sec = 1}, NULL); // 模拟读操作 // 加读锁 rwlock_rdlock(&lock); printf("Reader %d read data: %d\n", id, data); // 释放读锁 rwlock_unlock(&lock); } return 0; } int writer(void* arg) { int id = *(int*)arg; while (1) { thrd_sleep((struct timespec){.tv_sec = 2}, NULL); // 模拟操作 // 加锁 rwlock_wrlock(&lock); data++; printf("Writer %d write data: %d\n", id, data); // 释放锁 rwlock_unlock(&lock); } return 0; } int main(int argc, char const *argv[]) { // 初始化读写锁 rwlock_init(&lock); // 创建3个读线程 thrd_t readers[3]; int readerIds[3]; for (int i = 0; i < 3; i++) { readerIds[i] = i + 1; thrd_create(&readers[i], reader, &readerIds[i]); } // 创建2个线程 thrd_t writers[2]; int writerIds[2]; for (int i = 0; i < 2; i++) { writerIds[i] = i + 1; thrd_create(&writers[i], writer, &writerIds[i]); } // 等待所有线程结束 for (int i = 0; i < 3; i++) { thrd_join(readers[i], NULL); } for (int i = 0; i < 2; i++) { thrd_join(writers[i], NULL); } // 销毁读写锁 rwlock_destroy(&lock); return 0; } ``` 这个示例程序中有3个读线程和2个线程,读线程每隔1秒钟读一次共享变量data的值,线程每隔2秒钟一次共享变量data的值。读线程和线程之间会相互竞争读写锁,以实现对共享变量的并发访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值