zoukankan      html  css  js  c++  java
  • EasyDarwin开源流媒体服务器高性能设计之无锁队列

    本文来自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中。

    获取更多信息

    邮件:support@easydarwin.org

    WEB:www.EasyDarwin.org

    Copyright © EasyDarwin.org 2013-2016

    EasyDarwin

  • 相关阅读:
    Keepalived案例一:Keepalived双机热备(HA)精讲
    Linux服务器挂载ntfs移动硬盘
    RAC 单节点实例异常关闭,关键报错ORA--29770
    模拟等待事件:db file sequential read
    使用dbms_stats.gather_table_stats调整表的统计信息
    oracle rac常用的网络检查命令
    收集Oracle数据库中的SQL基线信息(一)基础信息收集
    Oracle 通过sql profile为sql语句加hint
    将指定SQL的执行计划从共享池删除的方法
    数据库什么时候建立索引?
  • 原文地址:https://www.cnblogs.com/babosa/p/5904667.html
Copyright © 2011-2022 走看看