Boost logo

Boost :

Subject: Re: [boost] [threadpool] version 22 with default pool
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2009-03-03 18:53:53


Hi Oliver,

----- Original Message -----
From: <k-oli_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Tuesday, March 03, 2009 10:28 PM
Subject: [boost] [threadpool] version 22 with default pool

>
> I've uploaded a new version of boost-threadpool.
>
> changes:
> * free-function get_default_pool() returning reference to static pool<
> unbounded_channel< fifo > >
> * task has new function result() returning the internal shared_future
> * future-like functions removed from task
> * boost-threadpool not a header-only library

First of all thanks for incorporating the get_default_pool() and result() functions and the default constructor for the task class. And also for changing jss by boost on the future file (BTW the reschedule_until example has jet some jss::)

I would preserv the future-like functions, but I can live without.

With the current reschedule_until prototype we can not made any generic algotithm.

    template< typename Pool, typename R >
    void reschedule_until( boost::shared_future< R > const&);

Fisrt because we need to give the pool type. Generic code is unable to know the pool type staticaly.
Second because the future parameter is too restrictive. In order the future be ready another thread (or task) must set the promise. The prototype I'm locking for is

    template< typename Predicate >
    void reschedule_until( Predicate cnd);

In order to achieve this, you need that the thread specific pointer tss_worker_ for the worker threads be unique for all the pools, so instead of been a member of the pool context it could be a static variable of the worker class.

    namespace this_task {
        template< typename Predicate >
        void reschedule_until( Predicate cnd) {
             worker* w( worker::tss_worker_.get() );
             BOOST_ASSERT( w);
             w->reschedule_until( cnd );
        }
    }

The worker class defines a reschedule_until member function as follows:

   template< typename Predicate >
   void worker::reschedule_until( Predicate cnd)
   { (*reschedule_until_ptr)( pool_ptr_, cnd); }

The class worker will store a reschedule_until_ptr function pointer and pointer to a banalised pool

   void * pool_ptr_;
   void (reschedule_until_ptr)(void*, function<bool()>);

The pool class will have a private static function that casts and forwards to the private member function.

    static void reschedule_until( void* pool, function<bool()> cnd) {
        static_cast<pool*>(pool)->reschedule_until_(cnd);
    }

The pool will give this function at the construction of the worker.

So the worker and the pool more decoupled. As the worker is no more a template class, its implementation can be on a .cpp file.

As I have already say in another post I don't know how to implement this_task::sleep with the current reschedule_until interface. I repost here an adapted version in case the message was lost.

"Oliver, I think that one of the use cases is to be able to implement with the public interface

namespace this_task {
    void sleep_until(t);
}

namespace this_task {
    namespace detail {
        struct time_reached {
            system_time& abs_time_;
            time_reached(system_time& abs_time) : abs_time_(abs_time) {}
            bool operator()() {
                return boost::get_system_time() >= abs_time_;
            }
        };
    }
    void sleep_until(system_time& abs_time) {
            detail::time_reached t(abs_time);
            this_task::reschedule_until(t);
    }
}

This sounds good, but as we don't want the user writes different code when the function will be called by a task or by a thread we need just to implement a sleep that depending on the kind of thread the function will reschedule or call to the thread version.
  
    void sleep_until(system_time& abs_time) {
        if (this_task::pressent()) {
            detail::time_reached t(abs_time);
            this_task::reschedule_until(t);
        } else {
            this_thread::sleep(abs_time);
        }
    }

So the function present() or any better name should be added.
"

Resuming, in order to implement this_task::sleep without blocking the worker thread we need:

    namespace this_task {
        template< typename Pool, typename Predicate >
        void reschedule_until(Predicate cnd);
    
        bool present();
    }

Oliver, let me know if have you found a way to implement this_task::sleep_until without blocking the current thread.

Thanks for all the good work already accomplished,
Vicente


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk