手撕读写锁性能测试

测试代码

基本思路
先用CountDownLatch (详见下节,并发用具) 同步子线程创建,然后,摁下计时器一次,开始测试。
再用另一个CountDownLatch 同步子线程完成任务的情况,最后再按一下计时器。

配置:
1个写线程,7个读线程。同时,内部控制读写次数,为了方便体现读写锁的性能与互斥锁的性能对比,直接调整内部循环的限制次数即可。

粗略的结果
在写的次数比读的次数要少得多时,读写锁性能比互斥锁要高。
在写得次数比读得次数差不多时,互斥锁性能比读写锁略高。

但是在开启代码优化后,只有写者数量少于读者数量的两个数量级左右,读写锁的性能才开始体现出来。

CountDownLatch startLatch(1);
CountDownLatch endLatch(8);
ReadWriteLock mtx;

int g_count = 0;

void write_something() {
	startLatch.wait();

	int count = 1000; // thread_local
	do {
		WriterLockGuard lock(::mtx);
		g_count++;
	} while (--count);

	endLatch.down();
}

void read_something() {
	startLatch.wait();

	int count = 100000; // thread_local
	do {

#ifndef TEST_RWLOCK
		WriterLockGuard lock(::mtx);
#else
		ReaderLockGuard lock(::mtx);
#endif

	} while (--count);

	endLatch.down();
}

int main()
{	
	using namespace std::chrono;
	std::vector<std::thread> threads;

	
	for (int i = 0; i != 7; ++i) {
		threads.push_back(thread(read_something));
	}

	for (int i = 0; i != 1; ++i) {
		threads.push_back(thread(write_something));
	}

	startLatch.down();
	auto start = std::chrono::system_clock::now();

	endLatch.wait();
	auto end = std::chrono::system_clock::now();
	
	cout << (g_count == 1000) << endl;
	cout << duration_cast<milliseconds>(end - start).count() << " ms" << endl;

	for (auto &th : threads) {
		th.join();
	}

	return 0;
}

读写锁实现代码

互斥锁 + 条件变量实现读写锁

class ReadWriteLock {
	std::atomic<int> nwait_;
	std::condition_variable isNotWriter_;
	std::mutex mtx_;

public:
	void reader_lock() {
		unique_lock<std::mutex> localGuard(mtx_);

		while (nwait_ < 0) {
			isNotWriter_.wait(localGuard);
		}

		nwait_++;
	}

	void reader_unlock() {
		lock_guard<std::mutex> localGuard(mtx_);
		
		if (--nwait_ == 0) isNotWriter_.notify_one();
	}

	void writer_lock() {
		unique_lock<std::mutex> localGuard(mtx_);

		while (nwait_ != 0) {
			isNotWriter_.wait(localGuard);
		}

		--nwait_;

		assert(nwait_ == -1);
	}

	void writer_unlock() {
		lock_guard<std::mutex> localGuard(mtx_);
		++nwait_;
		assert(nwait_ == 0);
		isNotWriter_.notify_all();
	}
};

双互斥锁实现读写锁

class ReadWriteLock {
	int nwait_;
	std::mutex rmtx_;
	std::mutex wmtx_;

public:

	ReadWriteLock() :nwait_(0) {}

	void reader_lock() {
		lock_guard<std::mutex> localGuard(rmtx_);
		++nwait_;
		if (nwait_ == 1) wmtx_.lock();

	}

	void reader_unlock() {
		lock_guard<std::mutex> localGuard(rmtx_);
		--nwait_;
		if (nwait_ == 0) wmtx_.unlock();
	}

	void writer_lock() {
		wmtx_.lock();

	}

	void writer_unlock() {
		wmtx_.unlock();
	}
};

并发用具

CountDownLatch

java常见的同步工具, 通常用于子线程全部完成任务后汇总给主线程

class CountDownLatch {
	size_t count_ = 0;
	std::mutex   mtx_;
	std::condition_variable cond_;

public:
	CountDownLatch(size_t count):count_(count) {
		assert(count >= 1);
	}

	void down() {
		unique_lock<std::mutex>  localGurad(mtx_);
		if (--count_ == 0) cond_.notify_all();
	}

	void wait() {
		unique_lock<std::mutex>  localGurad(mtx_);
		while (count_ != 0) cond_.wait(localGurad);
	}
};

LocalGuard

一些巧妙利用RALL机制的线程同步工具

读写锁相关

WriterLockGuard

class WriterLockGuard {
	ReadWriteLock &lock_;
public:
	WriterLockGuard(ReadWriteLock& lock) :lock_(lock) {
		lock_.writer_lock();
	}

	~WriterLockGuard() {
		lock_.writer_unlock();
	}
};

ReaderLockGuard:

class ReaderLockGuard {
	ReadWriteLock &lock_;
public:
	ReaderLockGuard(ReadWriteLock& lock) :lock_(lock){
		lock_.reader_lock();
	}

	~ReaderLockGuard() {
		lock_.reader_unlock();
	}
};

更多参考

Readers–writer lock

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值