栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

多缓存无锁极简实现

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多缓存无锁极简实现

双缓冲区方案
  • 双缓冲方案分配两段缓冲区:读(当前)缓冲和写(下一)缓冲。当执行查询操作时,总是读取当前缓冲区;当执行写操作时,总是在下一缓冲区上操作。当写操作执行完成后,交换操作会立刻将当前缓冲区和下一缓冲区交换,这样,最近更新的缓冲区便可供查询使用,旧的查询缓冲区用于写操作。
  • 示例代码:
template  
class DoubleBuffer {
public:
    DoubleBuffer():flag(false){}
    T* write() {
        return flag ? &buffer1 : &buffer2;
    }
    T* read() {
        return flag ? &buffer2 : &buffer1;
    }
    void swap() {
        flag = !flag;
    }
private:
    bool flag;
    T buffer1;
    T buffer2;
};


template  
class Updater {
public:
    T* reload_handler() {
        model.write()->clear();
        return model.write();
    }
    T* inc_handler() {
        *model.write() = *model.read();
        return model.write();
    }
    bool done() {
        model.swap();
    }
    T* read() {
        model.read();
    }
private:
    DoubleBuffer model;
};

使用

#include 
#include 
#include "Updater.hpp"
int main(){
    Updater > update_map;
    std::map *p = update_map.reload_handler();
    p->insert(std::make_pair(1, 100));
    p->insert(std::make_pair(2, 200));
    update_map.reload_handler()->insert();
    update_map.done();
    // update_map中存有:1 100   2 200
    std::map *pr = update_map.read();
    
    p = update_map.inc_handler();
    p->insert(std::make_pair(10, 100));
    p->insert(std::make_pair(20, 200));
    update_map.done();
    // update_map中存有:1 100   2 200   10 100    20 200
    pr = update_map.read();
}
安全性的考虑

1.在当前五分钟定时加载,每次加载时长两分钟左右,上述代码完全够用
2.代码依旧存在可能出现问题的情况,但是该可能微乎其微。
——当每次加载时长几乎和定时加载间隔相同时有可能出现如下问题——对正在读的缓冲执行写操作
1. 线程1中,更新操作w更新write_buffer
2. 线程2中,查询操作r指向read_buffer
3. 线程1中,更新操作w完成后执行交换
4. 线程2中ii步骤r操作持续,同时,线程1中新的更新操作开始。此时线程1和线程2会操作同一块内存
考虑到查询操作速度远高于更新操作,出现问题的的概率极低

改进方案 方案1: 计数

可以通过使用shared_ptr指针,看当前内存块引用数量是否仅为1,为1时再允许写操作,否则等待。

方案2: 三buffer方案

该方案增加一个缓冲区,分别称为只读buffer、只写buffer、读写隔离buffer
切换函数示例如下

void switch_buffer()
{
    *_cache_buffer = *_write_buffer;
    T* tmp = _write_buffer;
    _write_buffer = _cache_buffer;
    _cache_buffer = _read_buffer;
    _read_buffer = tmp;
}

以R、W、C分别表示只读buffer、只写buffer、读写隔离buffer;三块内存原始数据;r、w、c分别表示指向三块内存的指针;tmp为辅助指针;A、B、C三列为三个内存块,则上述流程可表示如下:

可以看出与双buffer相比,三buffer交换完成后将读指针切换到了最近更新的(写)内存,而旧的读内存块将持续存在一段时间,这一定程度保证了对旧内存块执行读操作的安全性。写操作则在第三块内存上执行。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/511664.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号