惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
P
Privacy & Cybersecurity Law Blog
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Project Zero
Project Zero
C
CERT Recently Published Vulnerability Notes
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cisco Blogs
博客园 - 司徒正美
L
LINUX DO - 热门话题
D
Docker
M
MIT News - Artificial intelligence
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
Jina AI
Jina AI
Last Week in AI
Last Week in AI
Security Latest
Security Latest
The Hacker News
The Hacker News
L
Lohrmann on Cybersecurity
Y
Y Combinator Blog
A
Arctic Wolf
小众软件
小众软件
T
Threat Research - Cisco Blogs
Know Your Adversary
Know Your Adversary
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
腾讯CDC
Google DeepMind News
Google DeepMind News
B
Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
I
Intezer
NISL@THU
NISL@THU
A
About on SuperTechFans
爱范儿
爱范儿
C
Cybersecurity and Infrastructure Security Agency CISA
D
Darknet – Hacking Tools, Hacker News & Cyber Security
G
Google Developers Blog
J
Java Code Geeks
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Cyberwarzone
Cyberwarzone
AWS News Blog
AWS News Blog
Engineering at Meta
Engineering at Meta
Latest news
Latest news

博客园 - cpunion

使用dpkt和pcap抓包 [收藏] jfwan实现的一个C++委托类 [c++] c++0x中的auto和typeof ACE_TP_Reactor的限制 ACE_SOCK_Stream send和recv超时设置 哀悼18位在车祸中死去的人 对ACE_TP_Reactor定时器处理机制做一点修改。 有趣的东西:Test () () () () () () () () () (); - cpunion VC2005 Beta 2 模板偏特化有些问题 [python] and or 表达式陷阱一则。 Media Player Classic外挂字幕时间调整脚本 我们的标准化委员会网站在哪? 不就是个座嘛 answers.com真是个不错的网站 《星际之门》和《亚特兰蒂斯》总算是更新了 生成gb2312码表 - cpunion - 博客园 [假如设计一个新语言] 哪些语言特性是我想要的 写一个CopyOnWrite的通用实现(C++) - cpunion - 博客园 Python写的一个适配器类。
C++编写“异步调用代理组件”的一点想法
cpunion · 2005-08-07 · via 博客园 - cpunion

注:里面使用了一个自己写的C++委托类Delegate,不是.net中的委托,关于这个委托详见我的C++委托类最终版。本文所写的代码是跨平台的纯C++实现。

一、简要说明。这里讲的异步调用代理组件,简要描述如下。假如有一个耗时的方法(不论它是本地调用还是远程调用),这个调用耗时的原因是由于某些原因的阻塞,比如IO,通常可以把这个操作交给一个线程去处理,为了通用、高效,往往会实现一个领导者/追随者线程池。常见的处理方式是把每一个调用封装为一个CALL对象,把参数存储在这个对象中,然后调用它的处理方法,在这个处理方法中调用实际的处理函数,返回值将会存储在CALL对象的一个成员变量中。从我使用过的框架来看,大部分是采用编写一个接口描述语言,并由一些工具自动生成相应的同步/异步调用过程。有的还要求你为每一个调用编写一个派生类,甚至需要另外一个类处理返回值或异常,这几个类完成一个同步->异步的映射,处理起来非常繁琐。这些复杂性都是由于线程模型的复杂性引起的。二、思路。我构思了一个异步调用的基础组件,大致描述如下:

1

、每一个调用需要绑定一个实际调用的函数call和一个处理调用结果的函数call_result,它们的类型映身如下:

a.

如果call类型是void(...),则call_result类型也是void(...)
b.
如果call类型是return_type(...),即有返回值的,则call_result类型是void(return_type, ...)假定这个类的名字是Call,那么它的使用方式是:

void call_1 (int);

void call_result_1 (int);

Call <void(int)> call_1 (call_1, call_result_1);

int call_2 (int);

void call_result_2 (int, int);

Call <void(int)> call_2 (call_2, call_result_2);其中还要求能够接受绑定了this指针的成员函数(实际上就是对象指针、成员函数指针对)、仿函数,前面做委托类时已经可以做到这点了,所以暂时不考虑细节。

2

、现在假如要完成一个异步调用,整个过程就包括:a.生成一个异步调用对象并返回b.工作线程取出调用对象并执行,调用完成并回调通知。以上面的call_1为例,这3个步骤如下:

a.

生成一个异步调用对象并返回:
// 生成调用并保存参数,放入处理队列

Call <void(int)>* pCall = new Call <void(int)>(call_1, call_result_1);

pCall->init_arguments (arguments);

asynch_call_queue.push(call_1);


b.
工作线程取出调用对象并执行:
CallBase* pCall = asynch_call_queue.front ();

asynch_call_queue.pop ();

pCall->call (); // 将执行调用并回调通知。

delete pCall; // 处理后事本文的重点并不在线程队列上,而是放在如何生成这个这个映射上面。三、实现。从上面可以整理出一个最简单的部分:
struct CallBase

{

    virtual ~CallBase () {}

    virtual void call () = 0;

};

typedef queue <CallBase*> AsynchCallQueue;

只要从CallBase上派生模板类Call即可,由于需要编写多个偏特化版本,比较耗时,这里先实现一个R(T)void(T)特化版本:

template <typename T>

class Call

{

     Call ();

};

template <typename Ret, typename A>

class Call <Ret(A)> : public CallBase

{

     typename Delegate <Ret(A)> _call;

     typename Delegate <void(Ret,A)> _call_result;

     Ret      _response;

     A        _param1;

public:

     template <typename F1, typename F2>

     Call (F1 f1, F2 f2)

     {

         _call += f1;

         _call_result += f2;

     }

     void init_arguments (A a)

     {

         _param1 = a;

     }

     virtual void call ()

     {

         _response = _call (_param1);

         _call_result (_response, _param1);

     }

};

template <typename A>

class Call <void(A)> : public CallBase

{

     typename Delegate <void(A)> _call;

     typename Delegate <void(A)> _call_result;

     A        _param1;

public:

     template <typename F1, typename F2>

     Call (F1 f1, F2 f2)

     {

         _call += f1;

         _call_result += f2;

     }

     void init_arguments (A a)

     {

         _param1 = a;

     }

     virtual void call ()

     {

         _call (_param1);

         _call_result (_param1);

     }

};

四、简单测试效果:

int test1 (int n)

{

     cout << "test1: " << n << endl;

     return 3;

}

void test1_result (int ret, int n)

{

     cout << "test1_result: " << ret << ", " << n << endl;

}

void test2 (int n)

{

     cout << "test2" << n << endl;

}

void test2_result (int n)

{

     cout << "test2_result: " << n << endl;

}

AsynchCallQueue asynch_call_queue;

// 此处三行定义是由于VC2005 Beta 2的一个偏特化BUG,如果不定义,则会提示无法决议。

// g++编译器下可以直接去掉这几行。

Delegate <void(int,int)> d;

Delegate <void(int)> d1;

Delegate <int(int)> d2;

int main ()

{

     // 生成调用并放入队列

     {

         Call <int(int)>* pCall1 = new Call <int(int)> (test1, test1_result);

         pCall1->init_arguments (3);

         asynch_call_queue.push (pCall1);

         Call <void(int)>* pCall2 = new Call <void(int)> (test2, test2_result);

         pCall2->init_arguments (5);

         asynch_call_queue.push (pCall2);

     }

     // 模拟另一线程取出并执行

     {

         CallBase* pCall;

         while (!asynch_call_queue.empty ())

         {

              pCall = asynch_call_queue.front ();

              pCall->call ();

              asynch_call_queue.pop ();

              delete pCall;

         }

     }

     return 0;

}

五、补充。

这里说的“异步调用代理组件”,其实就是Call类,由于使用了委托类,所以绑定异步调用更灵活。

本文只是简单的一点思路,离实用的距离还有:

1、   未加入线程池,未实现同步队列;

2、   模板类参数类型未严格约束,可能导致某些编译错误很难找出错误原因;

3、   这个模型没有处理“生成调用和回调处于同一线程”这个要求,这个会增加一些复杂度,比如需要为每个call映射线程ID、要为每个call分配全局唯一ID,为了让调用过程由线程池完成,调用结果由生成调用的线程完成,需要把这2个部分分离

4、   需要加入调用超时设置;

5、   基于第3条和第4条,还需要实现使用异步模型模拟同步调用机制;

6、这里给出的代码只适用于传值参数(指针也适合),引用类型暂未考虑。


以上只是现在的初步设想,可能有遗漏之处。

六、发点劳骚,提点建议。

我不明白为何C++标准不把委托置于标准之内,c++0x里面好像也没看到,不过还需要几年时间,也可能会加入。

另外在写委托模板类和这里的Call类时,就觉得处理不同个数的参数实在繁琐,假如C++模板中加入下面这个东西多好啊。。。(我称它为模板宏,其实就是加入一个typelist关键字并运行这种机制,相应还有valuelist,不过想法还不成熟)

template <typename Ret, typelist ArgTypes>

class Call <Ret(ArgTypes)>

{

     typename Delegate <Ret(ArgTypes)> _call;

     typename Delegate <void(Ret,ArgTypes)> _call_result;

     ArgTypes _params;

     Ret      _response;

public:

     template <typename F1, typename F2>

     Call (F1 f1, F2 f2)

     {

         _call += f1;

         _call_result += f2;

     }

     void init_arguments (ArgTypes args)

     {

         _params = args;

     }

     virtual void call ()

     {

         _response = _call (_params);

         _call_result (_response, _params);

     }

}

template <typename Ret, typelist ArgTypes>

class Call <Ret(ArgTypes)>

{

     typename Delegate <void(ArgTypes)> _call;

     typename Delegate <void(ArgTypes)> _call_result;

     ArgTypes _params;

public:

     template <typename F1, typename F2>

     Call (F1 f1, F2 f2)

     {

         _call += f1;

         _call_result += f2;

     }

     void init_arguments (ArgTypes args)

     {

         _params = args;

     }

     virtual void call ()

     {

          _call (_params);

         _call_result (_params);

     }

}

一个typelist就代替了这么多版本的偏特化,不知道这个想法是不是可行。