Back in 2010, Herb Sutter advocated the use of active objects instead of naked threads in an article on Dr. Dobb's.
Here is a C++11 version:
class Active {
public:
    typedef std::function<void()> Message;
    Active(const Active&) = delete;
    void operator=(const Active&) = delete;
    Active() : done(false) {
        thd = std::unique_ptr<std::thread>(new std::thread( [=]{ this->run(); } ) );
    }
    ~Active() {
        send( [&]{ done = true; } );
        thd->join();
    }
    void send(Message m) { mq.push_back(m); }
private:
    bool done;
    message_queue<Message> mq; // a thread-safe concurrent queue
    std::unique_ptr<std::thread> thd;
    void run() {
        while (!done) {
            Message msg = mq.pop_front();
            msg(); // execute message
        } // note: last message sets done to true
    }
};
The class can be used like this:
class Backgrounder {
public:
    void save(std::string filename) { a.send( [=] {
        // ...
    } ); }
    void print(Data& data) { a.send( [=, &data] {
        // ...
    } ); }
private:
    PrivateData somePrivateStateAcrossCalls;
    Active a;
};
I would like to support member functions with non-void return types. But I cannot come up with a nice design how to implement this, i.e. without using a container that can hold objects of heterogeneous types (like boost::any).
Any ideas are welcome, especially answers that make use of C++11 features like std::future and std::promise.
                        
This will take some work.
First, write
task<Sig>.task<Sig>is astd::functionthat only expects its argument to be movable, not copyable.Your internal type
Messagesare going to betask<void()>. So you can be lazy and have yourtaskonly support nullary functions if you like.Second, send creates a
std::packaged_task<R> package(f);. It then gets the future out of the task, and then moves thepackageinto your queue of messages. (This is why you need a move-onlystd::function, becausepackaged_taskcan only be moved).You then return the
futurefrom thepackaged_task.clients can grab ahold of the
std::futureand use it to (later) get the result of the call back.Amusingly, you can write a really simple move-only nullary task as follows:
but that is ridiculously inefficient (packaged task has synchronization stuff in it), and probably needs some cleanup. I find it amusing because it uses a
packaged_taskfor the move-onlystd::functionpart.Personally, I've run into enough reasons to want move-only tasks (among this problem) to feel that a move-only
std::functionis worth writing. What follows is one such implementation. It isn't heavily optimized (probably about as fast as moststd::functionhowever), and not debugged, but the design is sound:live example.
is a first sketch at a library-class move-only task object. It also uses some C++14 stuff (the
std::blah_taliases) -- replacestd::enable_if_t<???>withtypename std::enable_if<???>::typeif you are a C++11-only compiler.Note that the
voidreturn type trick contains some marginally questionable template overload tricks. (It is arguable if it is legal under the wording of the standard, but every C++11 compiler will accept it, and it is likely to become legal if it is not).