- 双缓冲方案分配两段缓冲区:读(当前)缓冲和写(下一)缓冲。当执行查询操作时,总是读取当前缓冲区;当执行写操作时,总是在下一缓冲区上操作。当写操作执行完成后,交换操作会立刻将当前缓冲区和下一缓冲区交换,这样,最近更新的缓冲区便可供查询使用,旧的查询缓冲区用于写操作。
- 示例代码:
templateclass 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
1.在当前五分钟定时加载,每次加载时长两分钟左右,上述代码完全够用
2.代码依旧存在可能出现问题的情况,但是该可能微乎其微。
——当每次加载时长几乎和定时加载间隔相同时有可能出现如下问题——对正在读的缓冲执行写操作
1. 线程1中,更新操作w更新write_buffer
2. 线程2中,查询操作r指向read_buffer
3. 线程1中,更新操作w完成后执行交换
4. 线程2中ii步骤r操作持续,同时,线程1中新的更新操作开始。此时线程1和线程2会操作同一块内存
考虑到查询操作速度远高于更新操作,出现问题的的概率极低
可以通过使用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交换完成后将读指针切换到了最近更新的(写)内存,而旧的读内存块将持续存在一段时间,这一定程度保证了对旧内存块执行读操作的安全性。写操作则在第三块内存上执行。



