По следам темы   eao197 слепил свою модель Ad-hoc легковесных недоакторов с помощью boost::asio::io_service и boost::signals2. Вот что получилось:
eao197 слепил свою модель Ad-hoc легковесных недоакторов с помощью boost::asio::io_service и boost::signals2. Вот что получилось:
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
#include <boost/asio/io_service.hpp>
#include <boost/signals2.hpp>
#define BOOST_TEST_MODULE Miscellaneous
#include <boost/test/unit_test.hpp>
namespace tests {
std::ostream&
print_one(std::ostream& os)
{
    return os;
}
template <class A0, class... Args>
std::ostream&
print_one(std::ostream& os, const A0& a0, const Args&... args)
{
    os << a0;
    return print_one(os, args...);
}
template <class... Args>
std::ostream&
print(std::ostream& os, const Args&... args)
{
    std::ostream& result = print_one(os, args...);
    os.flush();
    return result;
}
template <class... Args>
std::ostream&
print(const Args&... args)
{
    static std::mutex m;
    std::lock_guard<std::mutex> lg(m);
    return print(std::cout, args...);
}
class BaseActor {
public:
    BaseActor()
        : thread_()
    {
    }
    virtual ~BaseActor()
    {
        stop();
    }
    void start()
    {
        stop();
        io_service.reset();
        work_.reset(new boost::asio::io_service::work(io_service));
        std::thread(std::bind(&BaseActor::threadFunc_, this)).swap(thread_);
    }
    void stop()
    {
        work_.reset();
        io_service.stop();
        if (thread_.joinable())
            thread_.join();
    }
public:
    boost::asio::io_service io_service;
protected:
    virtual void threadFunc_() { io_service.run(); };
protected:
    std::thread thread_;
    std::unique_ptr<boost::asio::io_service::work> work_;
};
class ActorA : public BaseActor {
public:
    std::function<void(const int&)> getDoJobAInvoker()
    {
        return io_service.wrap(std::bind(&ActorA::doJobA_, this, std::placeholders::_1));
    }
    ~ActorA() { stop(); };
public:
    boost::signals2::signal<void(const std::string&)> helloSig;
    std::atomic_int aNumber{ 0 };
protected:
    virtual void threadFunc_()
    {
        print("ActorA has started", "\n");
        io_service.run();
        print("ActorA has finished", "\n");
    };
private:
    void doJobA_(const int& num)
    {
        print("ActorA::doJobA_() from thread ", thread_.get_id(), "\n");
        print("num = ", num, "\n");
        std::ostringstream oss;
        oss << "Hello, World " << num << "!";
        helloSig(oss.str());
        aNumber.store(num);
    }
};
class ActorB : public BaseActor {
public:
    std::function<void(const std::string&)> getDoJobBInvoker()
    {
        return io_service.wrap(std::bind(&ActorB::doJobB_, this, std::placeholders::_1));
    }
    ~ActorB() { stop(); };
public:
    boost::signals2::signal<void(const int&)> intSig;
protected:
    virtual void threadFunc_()
    {
        print("ActorB has started", "\n");
        io_service.run();
        print("ActorB has finished", "\n");
    };
private:
    void doJobB_(const std::string& str)
    {
        print("ActorB::doJobB_() from thread ", thread_.get_id(), "\n");
        print("str = ", str, "\n");
        intSig(++cout);
        aString_ = str;
    }
    int cout = 0;
    std::string aString_;
};
BOOST_AUTO_TEST_CASE(BoostIOServiceTest)
{
    print("Main thread id is ", std::this_thread::get_id(), "\n");
    ActorA actorA;
    ActorB actorB;
    actorA.helloSig.connect(actorB.getDoJobBInvoker());
    actorB.intSig.connect(actorA.getDoJobAInvoker());
    actorA.start();
    actorB.start();
    actorB.intSig(0);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
} // namespace tests
Этот код, разумеется, работает, и работает как положено, но есть у него недостаток: необходимо в деструкторах дочерних классов явно вызывать метод stop() базового класса, иначе велика вероятность, что при разрушении вызовется уже уничтоженный к этому времени сигнал, определенный в дочернем классе, а только потом остановится поток, который этот сигнал вызывает. Отсюда вопрос: как можно избавиться от необходимости явно вызывать BaseActor::stop() из деструкторов ActorA и ActorB?



