关闭

基于Boost的数据处理器及线程安全队列、跨平台的信号量和互斥锁

179人阅读 评论(0) 收藏 举报
分类:
近半年主要是开发公司行情系统Feedhandler(一共十几个Feedhandler,包括沪深L1、L2,港股,国内期货,国际股票,国际期货等。)。此系统要求跨平台、大吞吐量,超低延迟,属于CPU密集型系统。在项目过程中,有几个比较好的封装类,跟大家一起分享一下。以下所有源代码可至 http://download.csdn.net/detail/great3779/3998262 下载

一。基于Boost的跨平台锁。封装了Boost的mutex,提供了lock和unlock方法。代码示例如下:
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #pragma once  
  2.   
  3. // Author: Huangzhidan | great3779@sina.com   
  4. // copyright: @Wind Information Co., Ltd (Wind Info) ShangHai  
  5. // Create time: 2011-09-10  
  6. // 封装了boost的mutex,能跨平台使用。  
  7.   
  8. #include <boost/thread.hpp>  
  9.   
  10. class CWnLock  
  11. {  
  12. public:  
  13.     CWnLock(void) {}  
  14.     ~CWnLock(void) {}  
  15. public:  
  16.     virtual void lock() {m_lock.lock();}  
  17.     virtual void unlock() {m_lock.unlock();}  
  18. protected:  
  19.   boost::mutex m_lock;  
  20. };  

二。基于Boost的自动锁。相对之前的互斥锁,自动锁在发生异常时,能自动解锁,避免发生异常后,程序死锁。代码示例如下:
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. // WnScopedLock.h  
  2. #pragma once  
  3.   
  4. // Author: Huangzhidan | great3779@sina.com   
  5. // copyright: @Wind Information Co., Ltd (Wind Info) ShangHai  
  6. // Create time: 2011-09-10  
  7. // 封装了boost的mutex的scoped_lock,能跨平台使用。相对于CWnLock,其优势在于发生异常时能自动解锁,避免线程死锁。  
  8.   
  9. #include "WnLock.h"  
  10.   
  11. class CWnScopedLock : public CWnLock  
  12. {  
  13. public:  
  14.   CWnScopedLock(CWnLock& mutex);  
  15.   virtual ~CWnScopedLock(void);  
  16. public:  
  17.   virtual void lock() {return m_pMutex->lock();}  
  18.   virtual void unlock() {return m_pMutex->unlock();}  
  19. private:  
  20.   CWnLock* m_pMutex;  
  21. };  
  22.   
  23. // WnScopedLock.cpp  
  24. #include "WnScopedLock.h"  
  25.   
  26. CWnScopedLock::CWnScopedLock(CWnLock& mutex)  
  27. {  
  28.   m_pMutex = &mutex;  
  29.   m_pMutex->lock();  
  30. }  
  31.   
  32. CWnScopedLock::~CWnScopedLock(void)  
  33. {  
  34.   m_pMutex->unlock();  
  35. }  

三。基于Boost的事件信号通知。由于Boost原本的事件通知在使用时还需要带一把锁,使用过程也比较麻烦,不好理解。因此对其进行封装,封装后的CWnEvent类使用时类似Windows下的CEvent类,且能跨平台使用,效率也比较高(使用了之前的互斥锁和自动锁)。代码示例如下:
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #pragma once  
  2.   
  3. // Author: Huangzhidan | great3779@sina.com   
  4. // copyright: @Wind Information Co., Ltd (Wind Info) ShangHai  
  5. // Create time: 2011-09-10  
  6. // 封装了boost的condition_variable,使其使用方法很接近Windows的Event。其优势在于能跨平台使用。  
  7.   
  8. #include "WnLock.h"  
  9. #include "WnScopedLock.h"  
  10. #include <boost/thread.hpp>  
  11. #include <boost/date_time/posix_time/posix_time.hpp>  
  12.   
  13. class CWnEvent  
  14. {  
  15. public:  
  16.     CWnEvent(void){}  
  17.   virtual ~CWnEvent(void){}  
  18.   
  19. public:  
  20.   void wait()  
  21.     {  
  22.         CWnScopedLock scoped_lock(m_lock);  
  23.         m_condition.wait(scoped_lock);    
  24.     }  
  25.   
  26.     bool timed_wait(int nMillSec)  
  27.     {  
  28.         CWnScopedLock scoped_lock(m_lock);  
  29.         return m_condition.timed_wait(scoped_lock, boost::posix_time::millisec(nMillSec));  
  30.     }  
  31.   
  32.     void notify_one() { m_condition.notify_one(); }  
  33.   
  34.     void notify_all() { m_condition.notify_all(); }  
  35.   
  36. private:  
  37.   CWnLock m_lock;  
  38.   boost::condition_variable_any m_condition;  
  39. };  

四。一个非常高效、使用简单、扩展性强的数据处理器。此数据处理器主要优点如下:
1. 跨平台
2. 将线程通信间比较难的线程安全、信号通知等机制均封装在对象中
3. 由于数据的传递完全依靠事件通知,因此数据的流转效率以及吞吐量均非常高(已经使用在公司海外股票FeedHandler上,吞吐量轻松突破每秒500,000个包)
4. 接口简单,使用非常方便(可参考BoostDemo程序)
5. 由于采用了模板技术以及运行时绑定技术,因此可扩展性非常强。(公司FeedHandler项目,已经在CDataHandler类上派生了数十个类,扩展性非常好)

以下是示例代码:

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #pragma once  
  2.   
  3. // Author: Huangzhidan | great3779@sina.com   
  4. // copyright: @Wind Information Co., Ltd (Wind Info) ShangHai  
  5. // Create time: 2011-09-10  
  6.   
  7. // 一个可用于线程间传递数据的类。此类的优势在于:  
  8. // 1. 跨平台  
  9. // 2. 将线程通信间比较难的线程安全、信号通知等机制均封装在对象中  
  10. // 3. 由于数据的传递完全依靠事件通知,因此数据的流转效率以及吞吐量均非常高(已经使用在公司海外股票FeedHandler上,吞吐量轻松突破每秒500,000个包)  
  11. // 4. 接口简单,使用非常方便(可参考BoostDemo程序)  
  12.   
  13. // 使用方法  
  14. // CDataHandler是一个基类,使用时定义子类对其进行继承。  
  15. // 继承类重写DataThread和DataFunc方法(一般情况下仅需重写DataFunc方法即可)  
  16.   
  17. #include "AtomQueue/WnQueue.h"  
  18. #include "Synchronous/WnEvent.h"  
  19. #include <boost/thread.hpp>  
  20.   
  21. // a pure virtual function  
  22. template <class T> class CDataHandler  
  23. {  
  24. public:  
  25.     CDataHandler(void) {Start();}  
  26.     virtual ~CDataHandler() {}  
  27.   
  28. public:  
  29.     // 单个通知接口(一般不需调用)  
  30.     void NotifyOne() {m_event.notify_one();}  
  31.   
  32.     // 全部通知接口(一般不需调用)  
  33.     void NotifyAll() {m_event.notify_all();}  
  34.   
  35.     // 推入流数据  
  36.     void Put(T& t)  
  37.     {  
  38.         m_record_set.push(t);  
  39.   
  40.         // 发送通知信号  
  41.         m_event.notify_one();  
  42.     }  
  43.   
  44.     // 获取缓冲区buffer size的接口  
  45.     int BufferSize() { return m_record_set.size(); }  
  46.   
  47. protected:  
  48.     // 处理数据的线程,可在运行时绑定  
  49.     virtual void DataThread()  
  50.     {  
  51.         while(true)  
  52.         {  
  53.             m_event.wait();  
  54.             while(!m_record_set.empty())  
  55.             {  
  56.                 T t;  
  57.                 if(m_record_set.get(t))  
  58.                 {  
  59.                     DataFunc(t);  
  60.                 }  
  61.             }  
  62.         }  
  63.     }  
  64.   
  65.     // 处理数据的函数,可在运行时绑定  
  66.     virtual void DataFunc(T& t) {}  
  67.   
  68. // 以下为内部函数  
  69. protected:  
  70.     // 开始运行  
  71.     void Start()  
  72.     {  
  73.         boost::thread t(&CDataHandler::DataThread, this);  
  74.     }  
  75.   
  76. protected:  
  77.     // 流数据集  
  78.     CWnQueue<T> m_record_set;  
  79.   
  80.     // 信号  
  81.     CWnEvent m_event;     
  82. };  

基于此类的派生类使用,可以参考源代码:
http://download.csdn.net/detail/great3779/3998262


更新于20130701,在构造函数中,增加了可以设置消费线程数量以及缓冲区大小。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #pragma once  
  2.   
  3. // Author: Huangzhidan | great3779@sina.com   
  4. // copyright: @Wind Information Co., Ltd (Wind Info) ShangHai  
  5. // Create time: 2011-09-10  
  6.   
  7. // 一个可用于线程间传递数据的类。此类的优势在于:  
  8. // 1. 跨平台  
  9. // 2. 将线程通信间比较难的线程安全、信号通知等机制均封装在对象中  
  10. // 3. 由于数据的传递完全依靠事件通知,因此数据的流转效率以及吞吐量均非常高(已经使用在公司海外股票FeedHandler上,吞吐量轻松突破每秒500,000个包)  
  11. // 4. 接口简单,使用非常方便(可参考BoostDemo程序)  
  12.   
  13. // 使用方法  
  14. // CDataHandler是一个基类,使用时定义子类对其进行继承。  
  15. // 一般情况下仅需重写DataFunc方法即可(可满足99%需求)。如果对发包逻辑有特殊需求,则重写DataThread线程方法。  
  16.   
  17. // Revise: 2012-12-18  
  18. // 1. 与CWnQueue及CWnEvent的关系从依赖更新为继承,接口暴露更丰富且清晰.  
  19. // 2. 开放了缓冲区阈值设置,避免了系统缓冲区的溢出.  
  20.   
  21. // Revise: 20130731  
  22. // 1. 构造函数中能指定消费线程数据,做为一个多消费者数据处理机。  
  23. // 2. 增加了手动启动的接口  
  24.   
  25. #include "WnQueue.h"  
  26. #include "WnEvent.h"  
  27. #include <boost/thread.hpp>  
  28.   
  29. // a data processor handler.  
  30. template <class T> class CDataHandler : public CWnQueue<T>, public CWnEvent  
  31. {  
  32. public:  
  33.   ///< threadNum: 消费线程数目,默认为1  
  34.   ///< threshold: 内部缓冲区阈值,默认为无限  
  35.     CDataHandler(int threadNum = 1, bool autoStart = trueint threshold = 0) : m_thread_num(threadNum), m_threshold_size(threshold), m_bStart(false)  
  36.   {  
  37.     if(autoStart)  
  38.     {  
  39.       Start();  
  40.       m_bStart = true;  
  41.     }  
  42.   }  
  43.     virtual ~CDataHandler() {}  
  44.   
  45. public:  
  46.     // 推入元数据  
  47.     void Put(T& t)  
  48.     {  
  49.         push(t);  
  50.   
  51.     if(m_threshold_size > 0 && size() > m_threshold_size)  
  52.       clear();  
  53.     else  
  54.       notify_one(); // send semaphore  
  55.     }  
  56.   
  57. public:  
  58.   // start a run thread.  
  59.   void Start()  
  60.   {  
  61.     if(!m_bStart)  
  62.     {  
  63.       for(int i = 0; i < m_thread_num; ++i)  
  64.       {  
  65.         boost::thread t(&CDataHandler::DataThread, this);  
  66.       }  
  67.     }  
  68.   }  
  69.   
  70. public:  
  71.   ///< 设置消费线程数  
  72.   void SetThreadNum(int threadNum) {m_thread_num = threadNum;}  
  73.   
  74.   ///< 设置队列缓冲区阈值  
  75.   void SetBufferThreshold(int threshold) {m_threshold_size = threshold;}  
  76.   
  77. protected:  
  78.     // 数据处理线程. 如有特殊需要,请在子类中重写.   
  79.     virtual void DataThread()  
  80.     {  
  81.         while(true)  
  82.         {  
  83.             wait(); // wait semaphore  
  84.             while(!empty())  
  85.             {  
  86.                 T t;  
  87.                 if( get(t) )  
  88.                 {  
  89.                     DataFunc(t);  
  90.                 }  
  91.             }  
  92.         }  
  93.     }  
  94.   
  95.     // 数据处理核心函数,请在子类中重写!  
  96.     virtual void DataFunc(T& t) = 0;  
  97.   
  98. private:  
  99.   // 缓冲区阈值。一旦缓冲区达到此阈值,则清空所有缓冲区内容  
  100.   int m_threshold_size;  
  101.   
  102.   ///< 内部消费线程数目  
  103.   int m_thread_num;  
  104.   
  105.   ///< 处理机是否已启动的标识  
  106.   bool m_bStart;  
  107. };  
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:431982次
    • 积分:7411
    • 等级:
    • 排名:第2947名
    • 原创:288篇
    • 转载:248篇
    • 译文:1篇
    • 评论:23条
    最新评论