EasyDarwin

面向企业级的流媒体平台框架

EasyDarwin开始于2013年,遵循 Apple开源License APSL,为了敏捷流媒体服务器开发和简化企业流媒体应用开发而诞生的。

详细 >>

EasyDarwin开源流媒体服务器高性能设计之无锁队列


两个进程需要访问同一片共享内存,为了提高效率,我们不加锁(因为这两个进程都不能阻塞),A会定时更新共享内存,B会查询内存中的数据,A更新内存的操作不是原子操作,也就是说可能出现A更新一半,或者还没更新刚刚清空内存的时候,B来查询了,这样就会出现错误的结果。...

本文来自EasyDarwin团队Fantasy(fantasy(at)easydarwin.org)

一. EasyDarwin任务队列实现

EasyDarwin的任务队列是通过OSQueue类来组织的,操作方法有

EnQueue()插入一个节点

DeQueue()弹出一个节点

外面再经过一层封装,OSQueue_Blocking(),该类对OSQueue的操作都是加锁的,线程池的线程都是各自维护自己的队列,EventContext主循环往里投递事件,线程读取,处理。一边写一边读理论上来讲不需要加锁,但是这里加锁了。

原因是这样的,我们看EnQueue和DeQueue的实现,队列的前后两个队列之间是有联系的,有fNext和fPrev的关系,如果在读的时候,删除了fNext节点,就会出现空指针访问,导致段错误,这个就像是STL迭代器失效。

二. 针对一读一写去锁问题

大家可以学习一下内核的RCU机制,http://blog.csdn.net/nevil/article/details/7718375,通过缓存多份内存的方法避免读写冲突,举个很简单的例子,两个进程需要访问同一片共享内存,为了提高效率,我们不加锁(因为这两个进程都不能阻塞),A会定时更新共享内存,B会查询内存中的数据,A更新内存的操作不是原子操作,也就是说可能出现A更新一半,或者还没更新刚刚清空内存的时候,B来查询了,这样就会出现错误的结果。于是我们申请两块内存,A写的时候写内存块1,B查询内存块2,然后更换这两块内存的角色,这样就不会有冲突了。

三. EasyDarwin无锁队列实现

实现起来也比较简单,定一个合适长度的任务数组,目前定的是64

**#define MAX_QUEUE_ELEMS   64**
CyclicElem elems[MAX_QUEUE_ELEMS];

实现和OSQueue一模一样的接口

GetLength()获取有效任务个数

EnQueue()插入任务

DeQueue()弹出任务

int iread_pos;
int iwrite_pos;
int ivalid_elems; //定义读写位置,和有效元素个数变量。

初始化的时候都是0,如果处理的速度大于插入的速度,将不会有冲突,当读的速度小于写的速度的时候(这种情况下,我们认为队列超载,将丢弃任务),因此实现的时候,只要判断当写位置下一个位置就是读的位置的时候,我们认为写已经超过读一圈了,任务队列已满。具体实现在OSQueue.h中。



------------------------------ 分割线 ------------------------------
本站文章除注明转载外,均为本站原创或编辑,欢迎大家转载,但请务必注明出处,尊重他人成果,谢谢。
转载请注明:EasyDarwin;非本站文章均来自互联网,转载目的在于传递更多信息,并不代表本站赞同其观点和对其真实性负责。
文章中如果有错误可联系:johnson@easydarwin.org
推荐文章
安防和移动互联网行业比较火热的移动端手机......>
有人问到像美拍、秒拍这些短视频拍摄是怎么......>
最近更新
Easydarwin中大量使用gettimeofday来获取系......>
最近很多EasyDarwin爱好者提出了手机移动端......>
第一个到达的音频RTP包就将作为音频的关键帧......>
打开手机直播立即就能显示出主播视频,其实就......>
h264的功能分为两层,视频编码层(VCL)和网......>
友情链接 | 申请链接
EasyDarwin官方微信!