C++高并发场景下读多写少的解决方案 (2)

template <typename T, typename TLS> int DoublyBufferedData<T, TLS>::Read( typename DoublyBufferedData<T, TLS>::ScopedPtr* ptr) { // ScopedPtr析构的时候,会释放锁 Wrapper* w = static_cast<Wrapper*>(pthread_getspecific(_wrapper_key)); // 非首次读,获取pthread local lock if (BAIDU_LIKELY(w != NULL)) { w->BeginRead(); // 锁住 ptr->_data = UnsafeRead(); ptr->_w = w; return 0; } w = AddWrapper(); if (BAIDU_LIKELY(w != NULL)) { const int rc = pthread_setspecific(_wrapper_key, w); // 首次读,设置pthread local lock if (rc == 0) { w->BeginRead(); ptr->_data = UnsafeRead(); ptr->_w = w; return 0; } } return -1; }

template <typename T, typename TLS> template <typename Fn> size_t DoublyBufferedData<T, TLS>::Modify(Fn& fn) { BAIDU_SCOPED_LOCK(_modify_mutex); // 加锁,保证只有一个写 int bg_index = !_index.load(butil::memory_order_relaxed); // 指向后台buffer const size_t ret = fn(_data[bg_index]); // 修改后台buffer if (!ret) { return 0; } // 切指针 _index.store(bg_index, butil::memory_order_release); bg_index = !bg_index; // 等所有读老前台的线程读结束 { BAIDU_SCOPED_LOCK(_wrappers_mutex); for (size_t i = 0; i < _wrappers.size(); ++i) { _wrappers[i]->WaitReadDone(); } } // 确认没有读了,直接修改新后台数据,对其新前台 const size_t ret2 = fn(_data[bg_index]); return ret2; }

完整实现请参考brpc的DoublyBufferData

简单说说golang中双缓冲的实现 普通的双缓冲加载实现

基于计数器,用atomic,保证原子性,读进入临界区,计数器+1,退出-1,写判断计数器为0则切换,但计数器是全局锁。这种方案C++也可以采取,只是计数器毕竟也是全局锁,性能会差那么一丢丢。即使用智能指针shared_ptr,也会面临智能指针引用计数互斥的问题。之所以用计数器,而不用TLS,是因为go不支持TLS,对比TLS版本和计数器版本,TLS性能更优,因为没有抢计数器的互斥问题,但抢计数器本身很快,性能没测试过,可以试试。

sync.Map的实现

也是基于计数器,只是计数器是为了让读前台缓存失效的概率不要太高,有抑制和收敛的作用,实现了读的无锁,少部分情况下,前台缓存读不到数据的时候,会去读后台缓存,这时候也要加锁,同时计数器+1。计数器数值达到一定程度(超过后台缓存的元素个数),就执行切换

是否适用于读少写多的场景

不合适,双缓冲优先保证读的性能,写多读少的场景需要优先保证写的性能。

相关文献

brpc对于双buffer的描述:
go实现的双buffer(但读是互斥的,性能先对较差):
双buffer的三种实现方案:https://juejin.cn/post/6844904130989801479
一写多读:https://blog.csdn.net/lqt641/article/details/55058137
高并发下的系统设计:https://www.cnblogs.com/flame540/p/12817529.html
基于计数器的实现:https://www.cnblogs.com/gaoxingnjiagoutansuo/p/15773361.html#4998436

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzfgws.html