blog文章地址:http://godebug.org/index.php/archives/139/
前几天买了本七周七并发模型,看了里面关于Actor模型的介绍后觉得Actor这东西其实挺简单的,平时用asio写网络应用,每个session直接也是通过投递异步事件来互相交流的,本质上每个session类也就是一个Actor,看来着东西平时一直在用,只是不知道叫这么个名字罢了,再生搬硬套一个Actor模型感觉毫无意义,于是用asio写了个简单的比较通用的Actor模型。

#include <iostream>
#include <deque>
#include <boost/asio.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/smart_ptr.hpp>

template<typename T>
class Actor : public boost::enable_shared_from_this<Actor<T>>
{
public:
    Actor(boost::asio::io_service& service)
        :service_(service)
    {}
    ~Actor()
    {
        std::cout << "destroy" << std::endl;
    }

    void push_message(const T& msg)
    {
        bool is_runing = !msg_queue_.empty();
        msg_queue_.push_back(msg);
        if (!is_runing)
        {
            get_message();
        }
    }

protected:
    void get_message()
    {
        service_.post(boost::bind(&Actor<T>::do_get_message, shared_from_this()));
    }

    virtual void process_message(const T& msg) = 0;
private:
    void do_get_message()
    {
        process_message(msg_queue_.front());
        msg_queue_.pop_front();
        if (!msg_queue_.empty())
        {
            get_message();
        }
    }
    boost::asio::io_service& service_;
    std::deque<T> msg_queue_;
};

#include <boost/format.hpp>

class Actor1 : public Actor<int>
{
public:
    Actor1(boost::asio::io_service& service)
        :Actor<int>(service)
    {}

    void set_other(boost::shared_ptr<Actor<std::string>> other)
    {
        other_ = other;
    }

protected:
    virtual void process_message(const int& msg)
    {
        auto ptr = other_.lock();
        if (ptr)
        {
            ptr->push_message(boost::str(boost::format("receive: %d") % msg));
        }
    }
private:
    boost::weak_ptr<Actor<std::string>> other_;
};

class Actor2 : public Actor<std::string>
{
public:
    Actor2(boost::asio::io_service& service)
        :Actor<std::string>(service), num_(0)
    {}

    void set_other(boost::shared_ptr<Actor<int>> other)
    {
        other_ = other;
    }
protected:
    virtual void process_message(const std::string& msg)
    {
        std::cout << msg << std::endl;

        auto ptr = other_.lock();
        if (!ptr)
        {
            return;
        }

        if (++num_ == 100)
        {
            std::cout << "finished.." << std::endl;
            return;
        }
        ptr->push_message(num_);
    }

private:
    int num_;

    boost::weak_ptr<Actor<int>> other_;
};


int main()
{
    boost::asio::io_service service;

    boost::shared_ptr<Actor1> a1(boost::make_shared<Actor1>(service));
    boost::shared_ptr<Actor2> a2(boost::make_shared<Actor2>(service));
    a1->set_other(a2);
    a2->set_other(a1);
    a1->push_message(-1);


    service.run();
    return 0;
}

相信熟悉asio的人一定会觉得这代码这代码平淡无奇,看样我之前因为各种宣传一直把Actor当成解决并行问题的银弹了。当然因为C++没有模式匹配之类的语言限制,代码看起来比erlang差得很远也是原因之一。 如果要多线程跑的话,要记得给消息队列的操作加锁。