• 手撕读写锁性能测试


    测试代码

    基本思路
    先用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;
    }
    
    • 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
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    读写锁实现代码

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

    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();
    	}
    };
    
    • 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

    双互斥锁实现读写锁

    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();
    	}
    };
    
    • 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

    并发用具

    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);
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    LocalGuard

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

    读写锁相关

    WriterLockGuard

    class WriterLockGuard {
    	ReadWriteLock &lock_;
    public:
    	WriterLockGuard(ReadWriteLock& lock) :lock_(lock) {
    		lock_.writer_lock();
    	}
    
    	~WriterLockGuard() {
    		lock_.writer_unlock();
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ReaderLockGuard:

    class ReaderLockGuard {
    	ReadWriteLock &lock_;
    public:
    	ReaderLockGuard(ReadWriteLock& lock) :lock_(lock){
    		lock_.reader_lock();
    	}
    
    	~ReaderLockGuard() {
    		lock_.reader_unlock();
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    更多参考

    Readers–writer lock

  • 相关阅读:
    我的Flink学习笔记
    一张图让你牢记MySQL主从复制原理|原创
    【全网唯一有效】MacOS 12.4安装Parallels Desktop 17.1.x出现网络错误等等解决
    草稿纸-Java项目技术历史
    在uniapp中,如何去掉一些不想要的权限,
    【C++笔记】C++继承
    2020CCPC网络赛 杭电 6892 Lunch(题解+代码)
    python学习之【深拷贝】
    运营商大数据精准营销,击碎你的固化营销思维
    微前端二:qiankun
  • 原文地址:https://blog.csdn.net/u012342808/article/details/126022516