一概述

Streams框架是管道和过滤构架模式的一种实现,主要应用于处理数据流的系统。其实现以Task框架为基础。Task框架有两个特性非常适用于Streams框架:一是Task框架可用于创建独立线程的并发环境,这适合应用于ACE Streams框架中的主动过滤器;二是Task框架有统一的数据传输结果——消息队列,这适用于Streams框架中的管道。

二ACE_Task类

这里主要介绍与Streams框架相关的部分。

成员变量

 Task_T.h

 class ACE_Task : public ACE_Task_Base

 {

 /// Queue of messages on the ACE_Task..

   ACE_Message_Queue<ACE_SYNCH_USE, TIME_POLICY> *msg_queue_;

   /// true if should delete Message_Queue, false otherwise.

   bool delete_msg_queue_;

   /// Back-pointer to the enclosing module.

   ACE_Module<ACE_SYNCH_USE, TIME_POLICY> *mod_;

   /// Pointer to adjacent ACE_Task.

   ACE_Task<ACE_SYNCH_USE, TIME_POLICY> *next_;

 }

put函数

在ACE_Task框架中,put函数没有实际作用,在默认情况下,该函数没有执行任何操作,仅仅返回0.但是在Streams框架中,put函数与put_next函数结合起来可以实现数据在过滤器间的传输。如果put函数将数据保存在消息队列中,通过独立的线程来处理这些消息,那么它将成为一个主动过滤器;反之,如果put函数直接对数据进行处理,然后交给下一个过滤器,那么它就是一个被动过滤器。

 Task.cpp

 /// Default ACE_Task put routine.

 int

 ACE_Task_Base::put (ACE_Message_Block *, ACE_Time_Value *)

 {

   ACE_TRACE ("ACE_Task_Base::put");

   return ;

 }

put_next函数

如果在数据处理流水线有下一个过滤器,那么put_next函数用于将数据交给下一个过滤器处理。如下:

 Task_T.inl

 // Transfer msg to the next ACE_Task.

 template <ACE_SYNCH_DECL, class TIME_POLICY> ACE_INLINE int

 ACE_Task<ACE_SYNCH_USE, TIME_POLICY>::put_next (ACE_Message_Block *msg, ACE_Time_Value *tv)

 {

   ACE_TRACE ("ACE_Task<ACE_SYNCH_USE, TIME_POLICY>::put_next");

   return this->next_ ==  ? - : this->next_->put (msg, tv);

 }

next_指向的是有序过滤器的下一个过滤器。通过put_next函数,可以将数据交给下一个过滤器处理。

Streams框架应用示例

在这个示例中,我们将一个数据流的处理分为4步,在Streams框架中,将每个处理步骤称为一个Module:

  • Logrec_Reader:从文件中读取记录,然后交给下一个步骤。
  • Logrec_Timer:在记录尾部加上“format_data”
  • Logrec_Suffix:在记录尾部加上一个后缀——suffix
  • Logrec_Write:将记录显示在终端上

Logrec_Reader类

其是ACE_Task的子类,是一个主动对象类,有独立的控制线程,线程处理函数是svc。在Streams框架中,Logrec_Reader类是一个主动过滤器,代码如下:

 class Logrec_Reader : public ACE_Task<ACE_MT_SYNCH>
{
private:
ifstream fin; //标准输入流
public:
Logrec_Reader(ACE_TString logfile)
{
fin.open(logfile.c_str()); //ACE_TString.c_str() 转换为char
}
virtual int open (void *)
{
return activate();
} virtual int svc()
{
ACE_Message_Block *mblk;
int len = ;
const int LineSize = ;
char file_buf[LineSize]; while(!fin.eof())
{
fin.getline(file_buf, LineSize);
len = ACE_OS::strlen(file_buf);
ACE_NEW_RETURN(mblk, ACE_Message_Block(len + ), );
if (file_buf[len - ] == '\r')
{
len = len - ;
}
mblk->copy(file_buf, len);
// 通过put_next函数,将消息传递给下一个过滤器
put_next(mblk);
}
//构造一个MB_STOP消息
ACE_NEW_RETURN(mblk, ACE_Message_Block (, ACE_Message_Block::MB_STOP), );
put_next(mblk);
fin.close();
ACE_DEBUG((LM_DEBUG, "read svc return. \n"));
return ;
}
};

Logrec_Timer类

也是ACE_Task的子类,但是它不是主动对象类,没有创建独立线程。其实现了put函数,这个函数被它的上一个过滤器(Logrec_Reader)调用,并且数据直接在这个函数中处理。

这里for循环用于处理消息链表,在示例中并没有使用链表因此for循环只会执行一次。

 class Logrec_Timer : public ACE_Task<ACE_SYNCH>
{
private:
void format_data(ACE_Message_Block *mblk)
{
char *msg = mblk->data_block()->base();
strcat(msg, "format_data");
}
public:
virtual int put(ACE_Message_Block *mblk, ACE_Time_Value *)
{
for (ACE_Message_Block *temp = mblk;
temp != ; temp = temp->cont())
{
if (temp->msg_type() != ACE_Message_Block::MB_STOP)
{
format_data(temp);
}
}
return put_next(mblk);
}
};

Logrec_Suffix类

类似Logrec_Timer

 class Logrec_Suffix : public ACE_Task<ACE_SYNCH>
{
public:
void suffix(ACE_Message_Block *mblk)
{
char *msg = mblk->data_block()->base();
strcat(msg, "suffix\n");
}
virtual int put(ACE_Message_Block *mblk, ACE_Time_Value *)
{
for (ACE_Message_Block *temp = mblk;
temp != ; temp = temp->cont())
{
if (temp->msg_type() != ACE_Message_Block::MB_STOP)
{
suffix(temp);
}
}
return put_next(mblk);
}
};

Logrec_Write类

这里put函数由上一个过滤器(Logrec_Suffix)调用,其并没有对数据进行实际处理,只是将数据放入队列中,由线程独立处理。

 class Logrec_Write : public ACE_Task<ACE_SYNCH>
{
public:
virtual int open(void*)
{
ACE_DEBUG((LM_DEBUG, "Logrec_Writer.\n"));
return activate();
} virtual int put (ACE_Message_Block *mblk, ACE_Time_Value *to)
{
return putq(mblk, to);
} virtual int svc()
{
int stop = ;
for (ACE_Message_Block *mb; !stop && getq(mb) != -;)
{
if (mb->msg_type() == ACE_Message_Block::MB_STOP)
{
stop = ;
}
else{
ACE_DEBUG((LM_DEBUG, "%s", mb->base()));
}
put_next(mb);
}
return ;
}
};

Main

这里讲ACE_Module放入Streams中,ACE_Module才是真正数据处理的Module。ACE_Streams类有两个数据成员:stream_head_和stream_tail_,它们指向ACE_Module链表的首尾。对于每个Streams,其默认带有首尾两个Module,而后可以通过push将数据处理的Module放入执行链表中。每个Module包含两个Task,分别为读Task和写Task。在示例中仅注册了写Task,这些Module和Task通过next指针构成一个有序的串。

这里注意push有顺序要求,最后push即栈顶的为先执行的Module。

 int ACE_TMAIN(int argc, ACE_TCHAR *argv[])
{
if (argc != )
{
ACE_ERROR_RETURN((LM_ERROR, "usage: %s logfile\n", argv[]), );
} ACE_TString logfile (argv[]); ACE_Stream<ACE_SYNCH> stream; ACE_Module<ACE_MT_SYNCH> *module[];
module[] = new ACE_Module<ACE_MT_SYNCH>("Reader", new Logrec_Reader(logfile), , , ACE_Module<ACE_SYNCH>::M_DELETE_READER);
module[] = new ACE_Module<ACE_MT_SYNCH>("Formatter", new Logrec_Timer(), , , ACE_Module<ACE_SYNCH>::M_DELETE_READER);
module[] = new ACE_Module<ACE_MT_SYNCH>("Separator", new Logrec_Suffix(), , , ACE_Module<ACE_SYNCH>::M_DELETE_READER);
module[] = new ACE_Module<ACE_MT_SYNCH>("Writer", new Logrec_Write(), , , ACE_Module<ACE_SYNCH>::M_DELETE_READER); for ( int i = ; i >= ; --i )
{
if (stream.push(module[i]) == -)
{
ACE_ERROR_RETURN((LM_ERROR, "push %s module into stream failed.\n", module[i]->name()), );
}
ACE_DEBUG((LM_DEBUG, "push %s module into stream success. \n", module[i]->name()));
}
ACE_Thread_Manager::instance()->wait();
}

附完整代码及结果:https://github.com/ShiningZhang/ACE_Learning/tree/master/streams

 /*************************************************************************
> File Name: logrec.cpp
> Author:
> Mail:
> Created Time: Fri 13 Oct 2017 04:19:39 PM CST
************************************************************************/
#include <fstream>
#include <ace/Synch.h>
#include <ace/Task.h>
#include <ace/Message_Block.h>
#include <ace/Stream.h>
#include "ace/Thread_Manager.h"
#include <ace/Time_Value.h>
#include <ace/Module.h> using namespace std; class Logrec_Reader : public ACE_Task<ACE_MT_SYNCH>
{
private:
ifstream fin; //标准输入流
public:
Logrec_Reader(ACE_TString logfile)
{
fin.open(logfile.c_str()); //ACE_TString.c_str() 转换为char
}
virtual int open (void *)
{
return activate();
} virtual int svc()
{
ACE_Message_Block *mblk;
int len = ;
const int LineSize = ;
char file_buf[LineSize]; while(!fin.eof())
{
fin.getline(file_buf, LineSize);
len = ACE_OS::strlen(file_buf);
ACE_NEW_RETURN(mblk, ACE_Message_Block(len + ), );
if (file_buf[len - ] == '\r')
{
len = len - ;
}
mblk->copy(file_buf, len);
// 通过put_next函数,将消息传递给下一个过滤器
put_next(mblk);
}
//构造一个MB_STOP消息
ACE_NEW_RETURN(mblk, ACE_Message_Block (, ACE_Message_Block::MB_STOP), );
put_next(mblk);
fin.close();
ACE_DEBUG((LM_DEBUG, "read svc return. \n"));
return ;
}
}; class Logrec_Timer : public ACE_Task<ACE_SYNCH>
{
private:
void format_data(ACE_Message_Block *mblk)
{
char *msg = mblk->data_block()->base();
strcat(msg, "format_data");
}
public:
virtual int put(ACE_Message_Block *mblk, ACE_Time_Value *)
{
for (ACE_Message_Block *temp = mblk;
temp != ; temp = temp->cont())
{
if (temp->msg_type() != ACE_Message_Block::MB_STOP)
{
format_data(temp);
}
}
return put_next(mblk);
}
}; class Logrec_Suffix : public ACE_Task<ACE_SYNCH>
{
public:
void suffix(ACE_Message_Block *mblk)
{
char *msg = mblk->data_block()->base();
strcat(msg, "suffix\n");
}
virtual int put(ACE_Message_Block *mblk, ACE_Time_Value *)
{
for (ACE_Message_Block *temp = mblk;
temp != ; temp = temp->cont())
{
if (temp->msg_type() != ACE_Message_Block::MB_STOP)
{
suffix(temp);
}
}
return put_next(mblk);
}
}; class Logrec_Write : public ACE_Task<ACE_SYNCH>
{
public:
virtual int open(void*)
{
ACE_DEBUG((LM_DEBUG, "Logrec_Writer.\n"));
return activate();
} virtual int put (ACE_Message_Block *mblk, ACE_Time_Value *to)
{
return putq(mblk, to);
} virtual int svc()
{
int stop = ;
for (ACE_Message_Block *mb; !stop && getq(mb) != -;)
{
if (mb->msg_type() == ACE_Message_Block::MB_STOP)
{
stop = ;
}
else{
ACE_DEBUG((LM_DEBUG, "%s", mb->base()));
}
put_next(mb);
}
return ;
}
}; int ACE_TMAIN(int argc, ACE_TCHAR *argv[])
{
if (argc != )
{
ACE_ERROR_RETURN((LM_ERROR, "usage: %s logfile\n", argv[]), );
} ACE_TString logfile (argv[]); ACE_Stream<ACE_SYNCH> stream; ACE_Module<ACE_MT_SYNCH> *module[];
module[] = new ACE_Module<ACE_MT_SYNCH>("Reader", new Logrec_Reader(logfile), , , ACE_Module<ACE_SYNCH>::M_DELETE_READER);
module[] = new ACE_Module<ACE_MT_SYNCH>("Formatter", new Logrec_Timer(), , , ACE_Module<ACE_SYNCH>::M_DELETE_READER);
module[] = new ACE_Module<ACE_MT_SYNCH>("Separator", new Logrec_Suffix(), , , ACE_Module<ACE_SYNCH>::M_DELETE_READER);
module[] = new ACE_Module<ACE_MT_SYNCH>("Writer", new Logrec_Write(), , , ACE_Module<ACE_SYNCH>::M_DELETE_READER); for ( int i = ; i >= ; --i )
{
if (stream.push(module[i]) == -)
{
ACE_ERROR_RETURN((LM_ERROR, "push %s module into stream failed.\n", module[i]->name()), );
}
ACE_DEBUG((LM_DEBUG, "push %s module into stream success. \n", module[i]->name()));
}
ACE_Thread_Manager::instance()->wait();
}

test:

ACE-Streams架构简介及应用的更多相关文章

  1. LoadRunner系统架构简介

    1.LoadRunner系统架构简介 LoadRunner是通过创建虚拟用户来代替真实实际用户来操作客户端软件比如Internet Explorer,来向IIS.Apache等Web服务器发送HTTP ...

  2. crtmpserver的架构简介

    crtmpserver的架构简介 一.层 Layers . 机器层 Machine layer . 操作系统层 Operating System Layer   This layer is compo ...

  3. Extjs6官方文档译文——应用架构简介(MVC,MVVM)

    应用架构简介 Extjs 同时提供对于MVC和MVVM应用架构的支持.这两个架构方式共享某些概念,而且都旨在沿着逻辑层面划分应用程序代码.每种方法在选择如何划分应用组件上都有其各自的优势. 本指南的目 ...

  4. Kafka:架构简介【转】

    转:http://www.cnblogs.com/f1194361820/p/6026313.html Kafka 架构简介 Kafka是一个开源的.分布式的.可分区的.可复制的基于日志提交的发布订阅 ...

  5. LoadRunner系统架构简介与运行原理

    1.LoadRunner系统架构简介 LoadRunner是通过创建虚拟用户来代替真实实际用户来操作客户端软件比如Internet Explorer,来向IIS.Apache等Web服务器发送HTTP ...

  6. Cortex-M0(+)内核的处理器架构简介

    Cortex-M0(+)内核的处理器架构简介 2015年03月02日 16:51:12 阅读数:3158 系统架构 Cortex-M0处理器具有32位系统总线接口,以及32位地址线,即有4GB的地址空 ...

  7. 【转帖】LoadRunner系统架构简介

    LoadRunner系统架构简介: LoadRunner是通过创建虚拟用户来代替真实实际用户来操作客户端软件比如Internet Explorer,来向IIS.Apache等Web服务器发送HTTP协 ...

  8. TP 5.0 架构 简介

    TP 5.0 架构 简介 thinkphp 5.0 为API开发而设计的的高性能框架,是与以往thinkphp5.0以下版本大不相同的新型框架,病对以颠覆和重构版本,采用全新的架构思想,引入了更多的P ...

  9. ceph架构简介

    ceph架构简介 在测试OpenStack的后端存储时,看到了ceph作为后端存储时的各种优势 ,于是查询资料,总结了这篇ceph架构的博客,介绍了ceph的架构和ceph的核心组件.ceph整体十分 ...

随机推荐

  1. 【四边形不等式】noi95- 合并石子

    [题目大意] 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分.试设计出1个算法,计算出将N堆石子合并成 ...

  2. 【动态规划/多重背包问题】POJ2392-Space Elevator

    方法同POJ1014-Dividing,唯一不同点在于每一种block有最大限定高度a,故要以a为关键字进行排序,使得最大高度小的在前,否则最大高度小的再后可能放不上去. #include<io ...

  3. DP练习 巡逻

     国庆这天五一大道上人头攒动,这是因为大家都准备从五一广场上那个大屏幕观看新中国60周年的国庆阅兵式!这虽然是一件很喜庆的事情,可却让CS市的警察局长伤透了脑筋的,因为人潮拥挤是很容易发生安全事故的. ...

  4. linux基础命令学习(三)文件搜索 find

    1.使用name选项 查找自己的根目录$Home中的文件,可以用: find ~ -name "*.log" -print  查找当前目录下的文件,可以用: find . -nam ...

  5. 如何在Ubuntu中用firefox浏览器查看chm文档?

    首先下载这插 件:在firefox中点击“工具”->“附加软件”->“扩展”,在firefix扩展网页下搜索“"chmfox" 然后安装,重启后就可以了.

  6. html5开发<video>视频字幕的程序

    <!DOCTYPE html> <html lang="en"> <head>     <meta charset="utf-8 ...

  7. localhost与127.0.0.1的区别 2

    localhost与127.0.0.1的区别localhost与127.0.0.1的区别是什么?相信有人会说是本地ip,曾有人说,用127.0.0.1比localhost好,可以减少一次解析.看来这个 ...

  8. uva 1203 - Argus(优先队列)

    option=com_onlinejudge&Itemid=8&page=show_problem&problem=3644" target="_blank ...

  9. 【GISER&&Painter】Chapter02:WebGL中的模型视图变换

    上一节我们提到了如何在一张画布上画一个简单几何图形,通过创建画布,获取WebGLRendering上下文,创建一个简单的着色器,然后将一些顶点数据绑定到gl的Buffer中,最后通过绑定buffer数 ...

  10. Andorid之Annotation框架初使用(三)

    线程使用: @Background这个是使用了cached thread pool executor , 阻止开启过多的线程 可以为@Background指定一个id,用于随时终止线程的操作(Back ...