Boost logo

Boost :

Subject: Re: [boost] We need a coherent higher level parallelization story for C++ (was [thread] Is there a non-blocking future-destructor?)
From: Mikael Olenfalk (mikael.olenfalk_at_[hidden])
Date: 2015-10-13 04:39:49

On Tue, Oct 13, 2015 at 4:02 AM, Vicente J. Botet Escriba <
vicente.botet_at_[hidden]> wrote:

> Le 12/10/15 14:52, Hartmut Kaiser a écrit :
>> Sorry for cross-posting.
>> Vicente J. Botet Escriba wrote:
>>> I have a branch
>>> (
>>> that don't blocks on any future, but this will break async.
>> FWIW, the design decision to let those (and only those) futures block on
>> destruction which are returned from async was one of the really bad
>> decisions made for C++11, however that's just my opinion (others agree,
>> but
>> yet others disagree).
For what it is worth, I cannot figure out how to use future<> when the
destructor blocks as it "breaks" most of my usecases. Then again just
giving future a detach() member would solve it for me at least.

We (as a community) really need a higher level, over-arching approach which
>> ties all of the above together! My plan is to work on a corresponding
>> concept paper by the time of the committee meeting end of February 2016.
> I plan to update the N4414 Executors and Schedulers Revision 5 proposal as
> I believe that Executors must be copyable and lightweight.
> The new proposal P0008R0 comes back to executors that are not copyable and
> so left the responsibility of the the lifetime to the user (I'm
> experimenting it in branch make_executors_copyable)

(disclaimer: I haven't had time to play with the branch just yet)

I agree that making lifetime the problem of the user is not particularly
nice. I'd prefer to split the executors interface where only the part which
contains submit() is copyable and let the rest be non-copyable, we have
successfully used a similar design internally (it makes the interface which
is sent around and copied the smallest possible interface).

See below for an incomplete and badly named example.


// this code will not compile but hopefully you will be able to discern
what it is supposed to do:

class executor {
    // non-copyable
    typedef boost::work work;

    executor(executor const&) = delete;
    executor& operator=(executor const&) = delete;

    virtual ~executor() {};

    virtual void close() = 0;
    virtual bool closed() = 0;

    // can probably be non-virtual
    executor_sink create_sink(); // for lack of better name

    virtual bool try_executing_one() = 0;
    template <typename Pred>
    bool reschedule_until(Pred const& pred);

    // not in the current interface
    virtual void loop() = 0;

    shared_ptr<something> _something; // given to executor_sink

class executor_sink {
   // copyable
   typedef boost::work work;

   executor(shared_ptr<executor::something>); // public but only usable by
executor because something is private

   executor_sink(executor_sink&) = default;
   executor_sink& operator=(const executor_sink&) = default;

   bool closed() const
      if (auto shared_something = _something.lock())
        return shared_something->closed();
      return true;

   bool submit(work&& w)
      if (auto shared_something = _something.lock())
        return true;

      return false;

   weak_ptr<executor::something> _something;

Boost list run by bdawes at, gregod at, cpdaniel at, john at