用asio擼了一個簡單的Actor模型

網事已瘋發表於2015-05-14

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差得很遠也是原因之一。 如果要多執行緒跑的話,要記得給訊息佇列的操作加鎖。

相關文章