zoukankan      html  css  js  c++  java
  • 重温一下读写双缓冲问题

    好久没写过双缓存了,趁现在有空重新温习下。

    我们经常听说双缓存,但是很少使用多缓存,起码大多数情况下是这样吧。为什么不需要多缓冲呢,今天分析下。并不是缓冲区越多越好,这个需要考虑具体的应用场景。我们抽象假设一下应用场景,为了简化场景,假设只有一个读线程和一个写线程,设读时间为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;
    }
  • 相关阅读:
    【51nod1965】奇怪的式子
    【spoj】DIVCNTK
    【bzoj3173】最长上升子序列
    【UOJ 209】【UER #6】票数统计
    Fib数列2 费马小定理+矩阵乘法
    T37302 P哥的桶
    U32592 摘果实
    【loj6029】「雅礼集训 2017 Day1」市场&&【uoj#228】基础数据结构练习题
    【bzoj4631】踩气球 线段树
    [bzoj4922]Karp-de-Chant Number
  • 原文地址:https://www.cnblogs.com/openlib/p/5361888.html
Copyright © 2011-2022 走看看