C++并发编程框架Theron(4)——Hello world!

时间:2022-02-13 17:58:43

1 前言
  上一篇博文我主要介绍了Theron框架实践的入门知识,也就是如何搭建Theron框架环境以及各种编译时候的配置选择。从这篇博文开始,我们开始真正去了解如何编写Theron框架的程序。和其他语言学习一样,我们还是以经典的Hello world!打印作为Theron框架学习的入门程序,麻雀虽小五脏俱全,你会通过它学到Theron中线程间消息通信是如何实现的等等基本内容。
2 Hello world!
  尽管Theron功能十分强大,但是它使用起来也十分简单。Hello world!一个小小例子,大多需要知道的内容就可以提前学习到了。
  程序中,我们会创建一个简单的actor,当它收到消息自动调动消息处理函数来打印消息内容。此处我们将发送的消息是std::string类型,当actor收到一条std::string消息(程序中正是“Hello world!”),它就会自动立即打印出该内容。程序实现,一开始我们包含主要的Theron头文件:

#include <Theron/Theron.h> 

  接着,我们定义一个Printer actor。每个actor实质就是一个继承自Theron::Actor的C++类:

// 完成打印字符串的Actor 
// 继承自Theron::Actor.
class Printer : public Theron::Actor
{
public:
// 结构体, 传递framework给基类
Printer(Theron::Framework &framework) : Theron::Actor(framework)
{
// 注册消息处理函数
RegisterHandler(this, &Printer::Print);
}
private:
// std::string类型的消息处理函数
void Print(const std::string &message, const Theron::Address from)
{
// 打印字符串
printf("%s\n", message.c_str());
// 返回一个虚假(dummy)消息来实现同步
Send(0, from);
}
};

  我们可以认为一个actor就是一个具体类型的对象。不像传统的C++对象,actors和调用处后面的程序是并行异步执行的,沟通完全依靠消息。
  创建一个传统的C++对象,Printer类应该拥有一个公共方法叫做Print()用来接受std::string的参数。但是与之相反,这个叫Printer的actor并不包含公共方法,替换的是注册一个消息处理函数叫做Print()。处理函数是通过Printer构造函数来注册的,并且它会在任何收到一条std::string类型的消息的时候被立即执行。
  在程序中,Print()消息处理函数会发送一条虚假消息(一个int类型的0值)返回给发送者,用来实现同步。后面我们再讨论原因。
  上面已经定义了我们自己的actor,让我们在一个简单的程序中使用它:

int main() 
{
// 构造一个framework对象,并且实例化一个Printer的actor由它管理.
Theron::Framework framework;
Printer printer(framework);
// 构造一个receiver对象来接收actor的反馈消息
Theron::Receiver receiver;
// 发送一条消息给Printer.
// 我们传递receiver的地址当做'from'的地址
if (!framework.Send(
std::string("Hello world!"),
receiver.GetAddress(),
printer.GetAddress()))
{
printf("ERROR: Failed to send message\n");

}
// 使用虚假消息来实现同步,确保所有线程完成任务
receiver.Wait();

  首先我们创建一个Theron::Framework,并且在其中创建一个我们Printer的actor实例。Framework是一个作为actors宿主的管理类,并且这里我们传递它给actor构造函数。
  我们同时也会创建一个Theron::Receiver类,它可以看做是一位好心人,由于主函数没有当做actor注册的消息,所以它需要一个有家庭地址的“人”替它代收消息,Theron::Receiver类正是干这个活的。它的地址会用来接收actors反馈回来的消息。
  一切准备完毕,我们发送一条消息“Hello world!”给Printer让其打印。调用Framework::Send()是非阻塞的,它会在发送完消息后立即返回。以此同时,Print()消息处理函数会同步被一个与Printer actor关联的独立线程执行。
  异步消息传递的使用时Actor模型的核心思想。如果这里是通过一个传统的C++对象完成Printer,其中包含一个Print()方法,会请求一个外线程去同时访问actor的内部状态,使得这个actor变成非线程安全的对象。相反,Actor模型中Printer的内部状态仅可以被用来执行它的消息处理函数的线程所接近。Theron只可以一次执行每个actor的一个消息处理函数,而收到的消息是串行排列来处理的。所以每个actor是与生俱来地线程安全的,甚至当同时通过多个客户端发送多条消息。
  当通过Framework::Send()发送一条消息,我们需要提供两个地址:一个发送者的地址和一个接收者的地址。这里我们将本地的Receiver作为“from”地址,从而Printer可以发送一条确认消息给receiver,告诉它打印的任务已经完成了。
  主线程块调用了一次Receiver的Wait()方法,用来等待接收到actor的反馈消息才结束主线程,也就是整个进程。
  这块我们还是需要好好理解一下为什么需要一个Receiver对象。如果我们没有构造它,那么主线程运行到main()的结尾,从而会在Printer处理消息结束之前开始析构那个actor和framework。这样可能性的出现时因为Printer异步执行,并且与主线程并驾齐驱的。我们通过等待反馈消息的到来引入一些同步:同步actor的消息处理函数的结束来确保线程的结束。
3 小结
  在这个“Hello world!”实例中,我们通过程序了解了之前理论学习中几个重要的概念:actors,frameworks,messages和receivers。这几个对象是Theron框架简单程序实现的关键,也是复杂程序的基础单元。在后面,我们会接触更多的Theron框架的细节。
  以上是个人学习记录,由于能力和时间有限,如果有错误望读者纠正,谢谢!
  转载请注明出处:http://blog.csdn.net/FX677588/article/details/75194617


  参考文献:
  Theron框架官网http://www.theron-library.com/