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

转载 2016年08月28日 22:22:21
近半年主要是开发公司行情系统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. };  

守护进线程,互斥锁,信号量,队列,死锁递归锁等

守护进程: from multiprocessing import Process import os,time,random def task(): print('%s is runni...
  • sunv_lx
  • sunv_lx
  • 2017年12月05日 16:58
  • 12

Linux中线程同步:互斥锁/信号量/条件变量+无锁队列

基本概念互斥锁,条件变量,信号量 应用互斥锁POSIX线程锁机制的Linux实现都不是取消点,因此,延迟取消类型的线程不会因收到取消信号而离开加锁等待。值得注意的是,如果线程在加锁后解锁前被取消,锁...

linux多线程编程(C):信号量实现的线程安全队列

用信号量实现的线程安全队列。 简单有用的示例程序, 比起互斥量的实现在多线程时效率更好。 cir_queue.h /*  * \File  * cir_queue.h ...

python多进程笔记2 - 进程间通信:队列,管道,文件,共享内存,信号量,事件,互斥锁,socket

2017/11/4 进程间通信,进程池 进程间通信(IPC,inter-process communication):生产进程生产食物,消费进程购买食物,消费进程一直监视生产状况,只要一有食物就将其取...

进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)

一、管道 在Linux 中,管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现如下所述。 • 限制管道...

进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)

注:本分类下文章大多整理自《深入分析linux内核源代码》一书,另有参考其他一些资料如《linux内核完全剖析》、《linux c 编程一站式学习》等,只是为了更好地理清系统编程和网络编程中的一些概念...

多线程信号量,互斥锁,条件变量异同

多线程常见的几种同步方式总结: 只是阐述相关性,具体代码逻辑,网上一抓一大片,在此不在详述。 1、信号量: 主要用于线程之间的数据同步,比如A...

Linux多线程实践(五 )Posix信号量和互斥锁解决生产者消费者问题

一点区别: system v 信号量只能用于进程间同步,而posix 信号量除了可以进程间同步,还可以线程间同步。system v 信号量每次PV操作可以是N,但Posix 信号量每次PV只能是1。除...
  • NK_test
  • NK_test
  • 2016年01月03日 19:24
  • 3076

信号量与线程互斥锁的区别

援引CU上一篇帖子的内容: “信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在哪里)。而互斥锁是用在多线...
  • zacklin
  • zacklin
  • 2012年02月07日 15:15
  • 656
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于Boost的数据处理器及线程安全队列、跨平台的信号量和互斥锁
举报原因:
原因补充:

(最多只允许输入30个字)