服务器应用--双缓冲队列

在服务器开发中 通常的做法是 把 逻辑处理线程和I/O处理线程分离。

逻辑处理线程:对接收的包进行逻辑处理。

I/0处理线程:网络数据的发送和接收,连接的建立和维护。

通常 逻辑处理线程和I/O处理线程是通过数据队列来交换数据,就是生产者--消费者模型。

这个数据队列是多个线程在共享,每次访问都需要加锁,因此如何减少 互斥/同步的开销就显得尤为重要。

                                                                        解决方案:双缓冲队列

背景知识:

所谓双缓冲数据就是两个队列 一个负责从里写入数据,一个负责读取数据,当逻辑线程读完数据后负责将自己的队列和I/O线程的队列进行交换。

这样需要加锁的地方 有两个从队列中写入数据和两个队列进行交换时。如果是一块缓冲区,读,写操作是不分离的,双缓冲区起码节省了单缓冲区时读部分操作互斥/同步的开销。本质是采用空间换时间的优化思路。

缓冲区状态分析:

两个缓冲区分别对应着两个互斥锁locka,lockb,生产者消费者要控制那个缓冲区先要取得对应的锁。

1 并发读写

大多数情况下,生产者控制着某个队列进行写操作,消费者控制着另外一个队列进行读操作。

也就是说,逻辑线程和I/O线程进行着独占操作。这样就大大降低了互斥/同步的开销。

2 缓冲区切换

当消费者将自己的队列(对应locka)读完,立即释放对locka的控制,等待控制lockb。一旦生产者释放lockb,消费者立即控制lockb,开始 读取lockb对应的队列数据。同时生产者控制刚才locka,开始写操作。这样就完成队列交换。

这里注意的操作是无论生产者消费者在完成对自己的队列操作后一定要先释放锁资源再去尝试控制另外的队列。

因为如果生产者操作完成 不释放自己的锁 去尝试控制另外的锁,同时消费者也不释放资源也去尝试控制另外的锁,那么就会出现“死锁”。

队列交换策略分析:

优先保证读,即消费者完成对队列的操作后,立即进行交换。

一开始 两个队列都为空, 交换线程阻塞在生产者的条件变量处,工作线程阻塞在消费者条件变量处,生产者队列数据个数大于1 时 立即发出该条件通知,随即发生队列交换,交换完毕后发现,消费者队列数据个数大于1时 立即发出消费者条件变量通知,此时交换线程阻塞在消费者的条件变量处,工作线程结束等待开始处理数据,处理完毕等待交换线程发出的条件通知,同时发出工作现场结束工作的条件变量,通知交换线程继续进行工作。

要保证:

1 如果工作线程在处理数据 确保不进行队列交换 同时可以正常向生产者队列放入数据。

2 队列交换完毕后 交换线程 需要立即等待消费者线程执行完毕的条件通知,此时同时可以向生产者队列中放入数据。

3 消费者队列处理完毕需要做两个动作: 1 唤醒交换线程,发送对应的条件变量通知 2 等待交换线程完成一次队列交换的条件通知。

时间: 2024-10-11 16:46:43

服务器应用--双缓冲队列的相关文章

双缓冲队列来减少锁的竞争

双缓冲队列来减少锁的竞争 在日常的开发中,日志的记录是必不可少的.但是我们也清楚对同一个文本进行写日志只能单线程的去写,那么我们也经常会使用简单lock锁来保证只有一个线程来写入日志信息.但是在多线程的去写日志信息的时候,由于记录日志信息是需要进行I/O交互的,导致我们占用锁的时间会加长,从而导致大量线程的阻塞与等待. 这种场景下我们就会去思考,我们该怎么做才能保证当有多个线程来写日志的时候我们能够在不利用锁的情况下让他们依次排队去写呢?这个时候我们就可以考虑下使用双缓冲队列来完成. 所谓双缓冲

利用双缓冲队列来减少锁的竞争

在日常的开发中,日志的记录是必不可少的.但是我们也清楚对同一个文本进行写日志只能单线程的去写,那么我们也经常会使用简单lock锁来保证只有一个线程来写入日志信息.但是在多线程的去写日志信息的时候,由于记录日志信息是需要进行I/O交互的,导致我们占用锁的时间会加长,从而导致大量线程的阻塞与等待. 这种场景下我们就会去思考,我们该怎么做才能保证当有多个线程来写日志的时候我们能够在不利用锁的情况下让他们依次排队去写呢?这个时候我们就可以考虑下使用双缓冲队列来完成. 所谓双缓冲队列就是有两个队列,一个是

多线程操作C++ STL vector出现概率coredump问题及尽量避免锁的双缓冲队列

多线程操作全局变量,必须考虑同步问题,否则可能出现数据不一致, 甚至触发coredump. 前段时间, 遇到一个多线程操作了全局的vector的问题,  程序崩了.场景是这样的:某全局配置参数保存在一个vector中,需要定时更新(更新线程), 另外的工作线程去读取配置. 这种场景是非常普遍的. 在该场景中,程序没有枷锁,概率coredump, 实际情况是,服务跑了一段时间后,必然coredump.   很显然, 更新线程执行clear,然后在push_back操作时, 会导致工作线程的vect

双缓冲队列-减少生产者消费者锁的调用

在生产者-消费者模式中,我们常常会使用到队列,这个队列在多个线程共享访问时存在互斥和竞争操作, 意味着每次访问都要加锁.如何更好的如何减少锁竞争次数呢 ?今天要介绍的双缓冲队列就是个不错的选择. 双缓冲队列就是冲着同步/互斥的开销来的.我们知道,在多个线程并发访问同一个资源的时候,需要特别注意线程的同步问题.稍稍不注意,噢货,程序结果不正确了. 原理 直接上图: 这样为什么会减少锁的调用呢? 举个例子, 两个List,一个用来存,一个用来取.有点迷糊?就是有一个listP从工厂那里得到玩具对象,

双缓冲List

前言 声明:本文从Enode之父汤雪华QQ群里提取的,分享给各位小伙伴们供参考. 双缓冲,顾名思义为两个List,此设计用于解决收发分离过程中最大限度避免锁的竞争.有效的降低CPU开销.降低锁的竞争冲突而生. 应用场景 双缓冲List的设计思路,应用在多线程产生消息,单线程处理消息的场景. 设计思路 声明2个list,分别为_requestsWrite,_requestsRead,写入的消息放入_requestsWrite,读取从_requestsRead读取: 再声明一个bool类型的_has

C++11 实现生产者消费者双缓冲

基础的生产者消费者模型,生产者向公共缓存区写入数据,消费者从公共缓存区读取数据进行处理,两个线程访问公共资源,加锁实现数据的一致性. 通过加锁来实现 1 class Produce_1 { 2 public: 3 Produce_1(std::queue<int> * que_, std::mutex * mt_) { 4 m_mt = mt_; 5 m_que = que_; 6 m_stop = false; 7 } 8 void runProduce() { 9 while (!m_st

位图操作和双缓冲机制

位图操作代码部分: CRect rect;  GetClientRect(rect);  pDC->SetMapMode(MM_ANISOTROPIC);  pDC->SetWindowExt(rect.Width(), rect.Height());  pDC->SetViewportExt(rect.Width(), -rect.Height());  pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2); CDC MemDC

【MFC】MFC绘制动态曲线,用双缓冲绘图技术防闪烁

摘自:http://zhy1987819.blog.163.com/blog/static/841427882011614103454335/ MFC绘制动态曲线,用双缓冲绘图技术防闪烁 2011-07-14 10:34:54|  分类: 学习笔记 |  标签:双缓冲绘图技术  mfc  动态曲线   |举报 |字号 订阅 先上效果图 随着时间的推移,曲线向右平移,同时X轴的时间坐标跟着更新.一.如何绘制动态曲线. 所谓动画,都是一帧一帧的图像连续呈现在用户面前形成的.所以如果你掌握了如何绘制静

caffe数据读取的双阻塞队列说明

caffe的datareader类中 class QueuePair { public: explicit QueuePair(int size); ~QueuePair(); BlockingQueue<T*> free_; BlockingQueue<T*> full_; DISABLE_COPY_AND_ASSIGN(QueuePair); }; 这个就是双阻塞队列,先将free队列填充到最大长度,然后按照如下规则: 1,每当生产者push时,先将full队列pop,如果fu