好久没写过双缓存了,趁现在有空重新温习下。
我们经常听说双缓存,但是很少使用多缓存,起码大多数情况下是这样吧。为什么不需要多缓冲呢,今天分析下。并不是缓冲区越多越好,这个需要考虑具体的应用场景。我们抽象假设一下应用场景,为了简化场景,假设只有一个读线程和一个写线程,设读时间为rt,写时间为wt,有三种情况:
1、当 rt==wt时,也就是说,读时间等于写时间。这时候,开辟几个缓冲区好呢,应该是两个。看以下时间图(图画得水,看得懂就好)
重上面的图可以看出,从写1开始,写1完成后,读1开始同时写2,当读1完成时写2正好也完成,因此理论上,这重情况下使用双缓存就可以了。
2、当rt>wt时,即读快于写,也就是读的时间小于写的时间,那么这时候应该使用几个缓存呢?理论上应该不超过两个,看以下时间图
写的时间比读的长,写1开始,写1完成后,读1开始时同时开始写2。当读1完成时,写2还没写完,所以这时候,即使有再多的缓存也没用(这里不考虑多线程写),所以最多有两个缓存就够了。为了搞高性能,这里最好使用多线程写,当然了,要是多核cpu。
3、当rt<wt时,即写快于读,这时候理论上应该设置2到3个缓存区就够了。看图
这个就不解释了,因为前面有,都类似,读得慢,写的再快也没有多大意义(除了占空间)。
有考虑不到的情景,请多多指教,谢谢!上个代码:代码里对_read_list和_write_list进行上锁操作,只是为了同时满足那三种时间关系。若已确定了是哪两种模型,可以去掉锁采用更快的方法
char buffer1[1024]; char buffer2[1024];std::vector<char*> _buffer_list; std::vector<int> _read_list; // 可读缓存下标集合 std::vector<int> _write_list;// 可写缓存下标集合 std::mutex _mutex; // 同步锁 std::atomic<bool> _stopflag(false); // 全局停工标志void thread_read(Event* _er,Event* _ew) {while(!_stopflag){// 等待读if (_er->wait_for(std::chrono::milliseconds(2000))){while(true){// 检查可读缓存的下标集合int idx = -1;_mutex.lock();if (!_read_list.empty()){idx = *_read_list.begin();_read_list.erase(_read_list.begin());}_mutex.unlock();if (idx==-1){break;}// 进行写char* pbuffer = _buffer_list[idx];cout << pbuffer << endl;// 模拟读很慢//Sleep(500);// 加入可写,上锁_mutex.lock();_write_list.push_back(idx);_mutex.unlock();// 通知可写_ew->notify_all();}}// do other } }void thread_write(Event* _er,Event* _ew) {int global = 0;while(!_stopflag){// 等待写if (_ew->wait_for(std::chrono::milliseconds(2000))){while(true){// 检查可写缓存的下标集合int idx = -1;_mutex.lock();if (!_write_list.empty()){idx = *_write_list.begin();_write_list.erase(_write_list.begin());}_mutex.unlock();if (idx==-1)break;// 进行写char* pbuffer = _buffer_list[idx];memset(pbuffer,0,1024);sprintf(pbuffer,"this is threadid %i write %i buffer %i times",std::this_thread::get_id().hash(),idx,++global);// 加入可读_mutex.lock();_read_list.push_back(idx);_mutex.unlock();// 通知可读_er->notify_all();}}// do other } }int main() {_buffer_list.push_back(buffer1);_buffer_list.push_back(buffer2);Event event_read,event_write;std::list<std::thread> _list_thr;// 读线程_list_thr.push_back(std::thread(thread_read,&event_read,&event_write));// 写线程_list_thr.push_back(std::thread(thread_write,&event_read,&event_write));system("pause");// 开始时,全部缓存可写for (size_t i=0; i<_buffer_list.size(); ++i)_write_list.push_back(i);//通知写 event_write.notify_once();system("pause");_stopflag = true;for (auto& thr : _list_thr)thr.join();return 0; }