ACE 中的Active Object模式

 Active Object 设计模式:

       1) 根据对象被调用的方式,可以将对象分为两类:

        Passive Object和Active Object。Passive 和 Object和调用者在同一个线程中,这就是我们通常所用的函数调用。而Active Object和调用在不同的线程中,它有自己的控制线程。Active Object设计模式是一种应用于并发编程的设计模式,它通过解耦对象的访问和对象的执行来增加并发性,从而简化对象的同步访问。

        将方法的调用和方法的执行解耦。方法的调用在客户线程中,而方法的执行在另一个独立的线程中。另外,通过良性设计,使得客户端看起来就像是调用一个普通的方法。具体来说:我们用一个Proxy来描述Active Object的接口,由一个Servant来提供Active Object的实现。Proxy和Servant运行在两个不同的线程中,这样方法的调用和方法的执行就可以并发地运行了。其中Proxy运行在客户线程中,而Servant运行在另一个线程中。在运行期,Proxy将客户端的方法调用转化为方法请求,它们通过一个调度器保存在一个请求链表中,调度器运行在Servant线程中,它将方法请求从链表中取出,交由Servant执行。客户还可以获得运行结果。由于方法的调用和运行在不同的线程中,所以运行结果并不是立即返回的。客户只能通过阻塞等待或者循环查询的方式来获得运行结果,这个结果我们用Future来表示。

       2) 在Active Object设计模式中,有6个关键的参与者:

        Proxy:提供一个接口,客户通过该接口调用Active Object的方法。通过Proxy应用程序可以使用强类型的编程语言,而不是线程间松散的消息。Proxy位于客户线程中。

        方法请求(Method Request):方法请求类定义用于执行Active Object方法的接口。客户每次调用Proxy定义的方法,就会构造一个方法请求对象。一个方法请求包含了方法参数等上下文信息,这些上下文信息用于方法的执行和执行结果的返回。

        请求链表:Proxy将具体的方法请求对象插入到请求链表中。请求链表既用于保存方法请求,又用于判断方法请求的可执行性。请求链表将Proxy线程和Servant线程解耦,使得它们可以并发地运行。

        调度器(Scheduler):调度器运行于Active Object线程,用于调度方法请求。调度器使用请求链表来管理方法请求,调度的策略可以根据应用程序的实际需要进行选择。

        工作者(Servant):定义Active Object的行为和状态。工作者实现的方法需要与Proxy 接口、方法请求一致。当方法请求被调度器调度时,工作者的方法才会得到执行,因此,它总是运行在调度器线程中。

        结果(Future):客户通过Proxy调用一个方法,就可以接收到Future。Future使得客户可以获得方法调用的执行结果。由于客户的请求和方法的执行在不同的线程中,所以Future只能通过阻塞等待或者循环查询的方式获取。

       

#include "ace/Log_Msg.h"
#include "ace/OS.h"
#include "ace/Task.h"
#include "ace/Method_Request.h"
#include "ace/Future.h"
#include "ace/Activation_Queue.h"
#include <memory.h>
using namespace std;

#pragma comment(lib,"ace.lib")

// Servant 类对status_result_ 进行简单的累加工作

class Servant
{
public:
    Servant()
    {
        status_result_ = 1;
    }
    int status_update(void) 
    {
        ACE_DEBUG((LM_DEBUG, ACE_TEXT("Obtaining a status_update in %t ") ACE_TEXT("thread of control\n")));
        ACE_OS::sleep(2);
        return next_result_id();
    }
private:
    int next_result_id(void)
    {
        return status_result_++;  
    };
    int status_result_;
};

class StatusUpdate : public ACE_Method_Request
{
public:
    StatusUpdate(Servant & controller, ACE_Future<int>&returnval)
        : controller_(controller), returnVal_(returnval)
    {
        ACE_DEBUG((LM_DEBUG, "StatusUpdate::StatusUpdate.\n"));
    }
    virtual int call(void)
    {
        ACE_DEBUG((LM_DEBUG, "StatusUpdate::call.\n "));
        this->returnVal_.set(this->controller_.status_update());
        return 0;
    }
    
    private:
    Servant& controller_;
    ACE_Future<int> returnVal_;

};

class ExitMethod : public ACE_Method_Request
{
public:
    virtual int call(void)
    {
        return -1;
    }
};

// 调度器类
class Scheduler : public ACE_Task_Base
{
public:
    Scheduler()
    {
        ACE_DEBUG((LM_DEBUG, "Scheduler::Scheduler.\n"));
        this->activate();
    }

    virtual int svc(void)
    {
        ACE_DEBUG((LM_DEBUG, "Scheduler::svc.\n"));
        while(1)
        {
            auto_ptr<ACE_Method_Request>  request
            (this->activation_queue_.dequeue());
            if (request->call() == -1)
                break;
        }
        return 0;
    }

    int enqueue(ACE_Method_Request* request) 
    {
        ACE_DEBUG((LM_DEBUG, "Proxy::status_update.\n"));
        return this->activation_queue_.enqueue(request);
    }
    private:
    ACE_Activation_Queue activation_queue_;
};

        //既然在Active Object设计模式中使用了ACE_Activation_Queue作为消息队列,那么也就没有有必要使用ACE_Task类了,因为ACE_Task使用的消息队列是ACE_Message_Queue。

class Proxy
{
public:
    ACE_Future<int> status_update(void)
    {
        ACE_DEBUG((LM_DEBUG, "Proxy::status_update.\n"));
        ACE_Future<int> result;
        this->scheduler_.enqueue(new StatusUpdate(this->controller_, result));
        return result;
    }
    void exit(void)
    {
         ACE_DEBUG((LM_DEBUG, "Proxy::exit.\n"));
         this->scheduler_.enqueue(new ExitMethod);
    }
    private:
        Scheduler scheduler_;
        Servant controller_;
};

int ACE_TMAIN(int, ACE_TCHAR* [])
{
    Proxy controller;
    ACE_Future<int> results[10];
//客户通过Proxy接口发起累加方法请求
    for (int i = 0; i < 10; i++)
    results[i] = controller.status_update();
    ACE_OS::sleep(5);
//客户获取运行结果
    for (int j = 0; j < 10; j++)
    {
         int result = 0;
         results[j].get(result);
         ACE_DEBUG((LM_DEBUG, "[%D(%t)] result %d\n", result));
    }
    controller.exit();
    ACE_Thread_Manager::instance()->wait();
    return 0;
}  

运行结果如下: 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/479937.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux系统化学习】动静态库 | 软硬链接

目录 硬链接和软链接 硬链接 软链接 动态库和静态库 静态库 静态库的生成 静态库的使用 将库打包和使用 动态库 动态库的生成 动态库的使用 库搜索路径 硬链接和软链接 硬链接 上篇文章我们说到真正找到磁盘上的文件并不是文件名&#xff0c;而是inode。其实在…

pom.xml常见依赖及其作用

1.org.mybatis.spring.boot下的mybatis-spring-boot-starter&#xff1a;这个依赖是mybatis和springboot的集成库&#xff0c;简化了springboot项目中使用mybatis进行持久化操作的配置和管理 2.org.projectlombok下的lombok&#xff1a;常用注解Data、NoArgsConstructor、AllA…

linux-firewalld防火墙端口转发

目的:通过统一地址实现对外同一地址暴露 1.系统配置文件开启 ipv4 端口转发 echo "net.ipv4.ip_forward 1" >> /etc/sysctl.confsysctl -p 2.查看防火墙配置端口转发之前的状态 firewall-cmd --statefirewall-cmd --list-all 3.开启 IP 伪装 firewall-cm…

Docker chapter 6 镜像构建优化 - 依赖缓存 与 多阶段构建

old dockerfile # syntaxdocker/dockerfile:1FROM node:18-alpine WORKDIR /app RUN yarn install --production COPY . . CMD ["node", "src/index.js"] EXPOSE 3000 # syntaxdocker/dockerfile:1 是 Dockerfile 的一个解析器指令&#xff0c;它用于声明…

计算机网络基础入门指南

文章目录 网络分层模型OSI七层模型及其作用TCP/IP四层模型及作用为什么网络需要分层&#xff1f; 常见的网络协议应用层常见的协议传输层常见的协议网络层常见协议 从输入URL到页面展示的过程HTTP常见的状态码HTTP与HTTPS的区别HTTP是不保存状态的协议&#xff0c;如何保存用户…

FlinkCDC详解

1、FlinkCDC是什么 1.1 CDC是什么 CDC是Chanage Data Capture&#xff08;数据变更捕获&#xff09;的简称。其核心原理就是监测并捕获数据库的变动&#xff08;例如增删改&#xff09;&#xff0c;将这些变更按照发生顺序捕获&#xff0c;将捕获到的数据&#xff0c;写入数据…

【机器学习】数据清洗——基于Numpy库的方法删除重复点

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

代码随想录算法训练营day20

题目&#xff1a;530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先 参考链接&#xff1a;代码随想录 530.二叉搜索树的最小绝对差 思路&#xff1a;我一开始想到的方法是先生成中序序列&#xff0c;然后对相邻两项的差进行计算&#xff0c;取…

STM32使用软件SPI协议操作TFT18彩屏

时间记录&#xff1a;2024/2/20 一、SPI协议介绍 &#xff08;1&#xff09;SPI设备通过4根线进行通信&#xff0c;CS片选线&#xff0c;选择从设备&#xff0c;SCK时钟线&#xff0c;由主设备产生时钟&#xff0c;主机MOSI线连从机MISO线&#xff0c;由主机向从机发送信息&am…

Softing OPC UA SIS(安全集成服务器)最新版本集成了MQTT协议

Softing工业自动化的安全集成服务器软件&#xff08;Secure Integration Server, SIS&#xff09;最新版本新增了MQTT协议支持&#xff0c;为IT/OT云应用数据集成提供了更多的连接方案以及更高的安全性。 &#xff08;MQTT强化了安全集成服务器安全性和连接功能&#xff09; So…

阿里云服务器租用价格,2024年新版活动报价明细表

2024年阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服…

Sample Pairing(ICLR 2018)

paper&#xff1a;Data Augmentation by Pairing Samples for Images Classification 本文的创新点 本文提出了一种新的应用于图像分类的数据增强方法SamplePairing&#xff0c;这种简单的数据增强技术显著提高了所有测试的数据集的分类精度。此外当训练集中的样本数量非常少…