Review Request: future library (Gaskill version)

View: New views
20 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 - 3 - 4 - 5 - 6 | Next >

Re: Review Request: future library (N2561/Williams version)

by Peter Dimov-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

vicente.botet:
>>> I don't understand the need of this function. Could you show a use case
>>> for promise::get_future() function?
>>
>> promise::get_future() is the only way to get a future from a promise.
>> Since the whole point of using promise is to get the future, it's rather
>> pointless without it.
>
> why this is not an internal feautre?

You have to have a way to create the initial future, but for the "one time"
semantics one can have for example

    promise::promise( future& f );

instead of get_future.

FWIW, Braddock has argued (see the archives) that it's convenient to be able
to obtain a future from a promise, without the "one time" restriction.
("His" futures are "shared" though, as are "mine".) I argued that without
this feature, a promise can detect that no futures are left and can cancel
its task.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Review Request: future library (N2561/Williams version)

by Anthony Williams-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi all,

I have updated my prototype futures library implementation in light of various
comments received, and my own thoughts.

The new version is available for download, again under the Boost Software
License. It still needs to be compiled against the Boost Subversion Trunk, as
it uses the Boost Exception library, which is not available in an official
boost release.

Sample usage can be seen in the test harness. The support for alternative
allocators is still missing.

Changes

* I have removed the try_get/timed_get functions, as they can be replaced with
  a combination of wait() or timed_wait() and get(), and they don't work with
  unique_future<R&> or unique_future<void>.

* I've also removed the move() functions on unique_future. Instead, get()
  returns an rvalue-reference to allow moving in those types with move
  support. Yes, if you call get() twice on a movable type then the second
  get() returns an empty shell of an object, but I don't really think that's a
  problem: if you want to call get() multiple times, use a shared_future. I've
  implemented this with both rvalue-references and the boost.thread move
  emulation, so you can have a unique_future<boost::thread> if
  necessary. test_unique_future_for_move_only_udt() in test_futures.cpp shows
  this in action with a user-defined movable-only type X.

* Finally, I've added a set_wait_callback() function to both promise and
  packaged_task. This allows for lazy-futures which don't actually run the
  operation to generate the value until the value is needed: no threading
  required. It also allows for a thread pool to do task stealing if a pool
  thread waits for a task that's not started yet. The callbacks must be
  thread-safe as they are potentially called from many waiting threads
  simultaneously. At the moment, I've specified the callbacks as taking a
  non-const reference to the promise or packaged_task for which they are set,
  but I'm open to just making them be any callable function, and leaving it up
  to the user to call bind() to do that.

I've left the wait operations as wait() and timed_wait(), but I've had a
suggestion to use wait()/wait_for()/wait_until(), which I'm actively
considering.

Please download it, try it out, and let me know what you think.

Anthony
--
Anthony Williams            | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Review Request: future library (N2561/Williams version)

by Vicente Botet Escriba :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

----- Original Message -----
From: "Anthony Williams" <anthony_w.geo@...>
To: <boost@...>
Sent: Sunday, May 11, 2008 11:53 AM
Subject: Re: [boost] Review Request: future library (N2561/Williams version)


> Hi all,
>
> I have updated my prototype futures library implementation in light of
> various
> comments received, and my own thoughts.
>
> The new version is available for download, again under the Boost Software
> License. It still needs to be compiled against the Boost Subversion Trunk,
> as
> it uses the Boost Exception library, which is not available in an official
> boost release.

Hi,

Sorry for the question, but where can we download the new version? I have
followed the old link
http://www.justsoftwaresolutions.co.uk/files/n2561_future.hpp
and there is no modification.

Best

Vicente


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Review Request: future library (N2561/Williams version)

by Anthony Williams-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

"vicente.botet" <vicente.botet@...> writes:

> ----- Original Message -----
> From: "Anthony Williams" <anthony_w.geo@...>

>> I have updated my prototype futures library implementation in light of
>> various
>> comments received, and my own thoughts.
>>
>> The new version is available for download, again under the Boost Software
>> License. It still needs to be compiled against the Boost Subversion Trunk,
>> as
>> it uses the Boost Exception library, which is not available in an official
>> boost release.
>
> Hi,
>
> Sorry for the question, but where can we download the new version? I have
> followed the old link
> http://www.justsoftwaresolutions.co.uk/files/n2561_future.hpp
> and there is no modification.

Oops. It's

http://www.justsoftwaresolutions.co.uk/files/n2561_futures_revised_20080511.zip

Anthony
--
Anthony Williams            | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Review Request: future library (N2561/Williams version)

by Johan Torp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Nice work! Let's hope we can all agree on a best interface - and get it standardized directly :)

Anthony Williams-3 wrote:
* Finally, I've added a set_wait_callback() function to both promise and
  packaged_task. This allows for lazy-futures which don't actually run the
  operation to generate the value until the value is needed: no threading
  required. It also allows for a thread pool to do task stealing if a pool
  thread waits for a task that's not started yet. The callbacks must be
  thread-safe as they are potentially called from many waiting threads
  simultaneously. At the moment, I've specified the callbacks as taking a
  non-const reference to the promise or packaged_task for which they are set,
  but I'm open to just making them be any callable function, and leaving it up
  to the user to call bind() to do that.
If you haven't, please read my concerns about direct callbacks in http://www.nabble.com/Review-Request%3A-future-library-%28Gaskill-version%29-to16600402.html

Anthony Williams-3 wrote:
I've left the wait operations as wait() and timed_wait(), but I've had a
suggestion to use wait()/wait_for()/wait_until(), which I'm actively
considering.
I like timed_wait because that's the same name as in condition_variable. wait_until could be confusing - one might think the thread will wait until the specified time regardless of the future is set or not. time_limited_wait or wait_max_time are further alternatives.

Best Regards, Johan

Re: Re view Request: future library (N2561/Williams version)

by Anthony Williams-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Johan Torp <johan.torp@...> writes:

> Nice work! Let's hope we can all agree on a best interface - and get it
> standardized directly :)

Yes, I hope so.

> Anthony Williams-3 wrote:
>>
>> * Finally, I've added a set_wait_callback() function to both promise and
>>   packaged_task. This allows for lazy-futures which don't actually run the
>>   operation to generate the value until the value is needed: no threading
>>   required. It also allows for a thread pool to do task stealing if a pool
>>   thread waits for a task that's not started yet. The callbacks must be
>>   thread-safe as they are potentially called from many waiting threads
>>   simultaneously. At the moment, I've specified the callbacks as taking a
>>   non-const reference to the promise or packaged_task for which they are
>> set,
>>   but I'm open to just making them be any callable function, and leaving
>> it up
>>   to the user to call bind() to do that.
>>
>
> If you haven't, please read my concerns about direct callbacks in
> http://www.nabble.com/Review-Request%3A-future-library-%28Gaskill-version%29-to16600402.html

I have read your comments. My primary reason for including this came from
thread pools: if you know that the current thread (from the pool) is blocked
on a future related to a task in the pool, you can move it up the queue, or
maybe even invoke on the blocked thread. Braddock suggested lazy futures, and
I think that's also an important use case. For one thing, it shows that
futures are useful without thread pools: you can use them in single-threaded
code.

> Anthony Williams-3 wrote:
>>
>> I've left the wait operations as wait() and timed_wait(), but I've had a
>> suggestion to use wait()/wait_for()/wait_until(), which I'm actively
>> considering.
>>
>
> I like timed_wait because that's the same name as in condition_variable.
> wait_until could be confusing - one might think the thread will wait until
> the specified time regardless of the future is set or not. time_limited_wait
> or wait_max_time are further alternatives.

This was alongside a suggestion that we change the names for
condition_variable waits. The important part was the separation of
timed_wait(duration) vs timed_wait(absolute_time) with distinct names, so it
was clear which you were calling, and you wouldn't accidentally pass a
duration when you meant a fixed time point.

We could go for timed_wait_for() and timed_wait_until(), but they strike me as
rather long-winded. Maybe that's a good thing ;-)

Anthony
--
Anthony Williams            | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Re view Request: future library (N2561/Williams version)

by Johan Torp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Anthony Williams-3 wrote:
I have read your comments. My primary reason for including this came from
thread pools: if you know that the current thread (from the pool) is blocked
on a future related to a task in the pool, you can move it up the queue, or
maybe even invoke on the blocked thread. Braddock suggested lazy futures, and
I think that's also an important use case. For one thing, it shows that
futures are useful without thread pools: you can use them in single-threaded
code.
I don't quite understand you. What is the "current" thread in a thread pool? If there are dependencies between tasks in a thread-pool, shouldn't prioritizing be the task of an external scheduler - and solved before the tasks are initiated? I'd like to know your thoughts on what the thread pool should be and what problems it should solve more specifically than what's explained in N2276.

I thought the most common use case for futures was the active object pattern. We should all try to agree what use cases/design patterns/higher level abstractions are most important and which we want to support. IMHO, this should be top priority for the "future ambition". Even though no higher level abstractions built on futures will make it to C++0x or boost anytime soon, it's important that the future interface needn't change to support them in the - future :)

To me, being able to wait for any or all of a number of futures seems like an important use case. I'd use it to implement "i'm waiting on the result of a number of time-consuming commands and queries". Maybe this is implemented better in another way - any ideas?

Anthony Williams-3 wrote:
This was alongside a suggestion that we change the names for
condition_variable waits. The important part was the separation of
timed_wait(duration) vs timed_wait(absolute_time) with distinct names, so it
was clear which you were calling, and you wouldn't accidentally pass a
duration when you meant a fixed time point.

We could go for timed_wait_for() and timed_wait_until(), but they strike me as
rather long-winded. Maybe that's a good thing ;-)
Yes, long names is a good thing :)  duration_timed_wait/absolute_timed_wait are other alternatives.
duration and absolute_time will have two different types, right? If so I don't think they should have different function names because:
- IMO it doesn't increase code readability to repeat type information in symbol names
- It reduces genericity. Function overloading can be used to implement LSP for generic functions.

template<class TimeType>
void foo_algorithm(future<void>&f, TimeType t)
{
   ... do stuff ...
   f.timed_wait(t); // LSP for TimeType, more generic
}

I vote for 2 x time_limited_wait.

Best Regards, Johan

Re: Re view Request: future library (N2561/Williams version)

by Anthony Williams-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Johan Torp <johan.torp@...> writes:

> Anthony Williams-3 wrote:
>>
>> I have read your comments. My primary reason for including this came from
>> thread pools: if you know that the current thread (from the pool) is
>> blocked
>> on a future related to a task in the pool, you can move it up the queue,
>> or
>> maybe even invoke on the blocked thread. Braddock suggested lazy futures,
>> and
>> I think that's also an important use case. For one thing, it shows that
>> futures are useful without thread pools: you can use them in
>> single-threaded
>> code.
>>
>
> I don't quite understand you. What is the "current" thread in a thread pool?

In this case I mean the thread that called some_future.wait().

> If there are dependencies between tasks in a thread-pool, shouldn't
> prioritizing be the task of an external scheduler - and solved before the
> tasks are initiated? I'd like to know your thoughts on what the thread pool
> should be and what problems it should solve more specifically than what's
> explained in N2276.

Suppose you're using a thread pool to provide a parallel version of
quick-sort. The easiest way to do that is to partition the values into those
less than and those not-less-than the chosen pivot (as you would for a
single-threaded version), and submit tasks to the thread pool to sort each
half and then waits for them to finish. This doubles the number of tasks with
each level of recursion. At some point the number of tasks will exceed the
number of threads in the pool, in which case you have some tasks waiting on
others that have been submitted to the pool but not yet scheduled.

If you can arrange for the implementation to identify this scenario as it
happens, and thus schedule the task being waited for to run on the waiting
thread, you can achieve greater thread reuse within the pool, and reduce the
number of blocked threads.

One way to do this is have the pool use packaged_tasks internally, and set a
wait callback which is invoked when a thread waits on a future from a pool
task. When the callback is invoked by the waiting thread (as part of the call
to wait()), if that waiting thread is a pool thread, it can proceed as
above. If not, then it might arrange to schedule the waited-for task next, or
just do nothing: the task will get its turn in the end.

> I thought the most common use case for futures was the active object
> pattern.

That's one possible use. I wouldn't have pegged it as "most common" unless
you're considering all cases of a background thread performing operations for
a foreground thread as uses of active object.

> We should all try to agree what use cases/design patterns/higher
> level abstractions are most important and which we want to support. IMHO,
> this should be top priority for the "future ambition". Even though no higher
> level abstractions built on futures will make it to C++0x or boost anytime
> soon, it's important that the future interface needn't change to support
> them in the - future :)

I agree we should think about the higher-level abstractions we want to
support, to ensure the "futures" abstraction provides the necessary
baseline. I'd like higher-level stuff to be built on top of C++0x futures
without having to replace them with a different low-level abstraction that
provides a similar feature set.

> To me, being able to wait for any or all of a number of futures seems like
> an important use case. I'd use it to implement "i'm waiting on the result of
> a number of time-consuming commands and queries". Maybe this is implemented
> better in another way - any ideas?

Waiting for one of a number of tasks is an important use case. I'm not sure
how best to handle it. I've seen people talk about "future_or" and "f1 || f2",
but I'm not sure if that's definitely the way to go.

> Anthony Williams-3 wrote:
>>
>> This was alongside a suggestion that we change the names for
>> condition_variable waits. The important part was the separation of
>> timed_wait(duration) vs timed_wait(absolute_time) with distinct names, so
>> it
>> was clear which you were calling, and you wouldn't accidentally pass a
>> duration when you meant a fixed time point.
>>
>> We could go for timed_wait_for() and timed_wait_until(), but they strike
>> me as
>> rather long-winded. Maybe that's a good thing ;-)
>>
>
> Yes, long names is a good thing :)  duration_timed_wait/absolute_timed_wait
> are other alternatives.
> duration and absolute_time will have two different types, right? If so I
> don't think they should have different function names because:
> - IMO it doesn't increase code readability to repeat type information in
> symbol names
> - It reduces genericity. Function overloading can be used to implement LSP
> for generic functions.
>
> template<class TimeType>
> void foo_algorithm(future<void>&f, TimeType t)
> {
>    ... do stuff ...
>    f.timed_wait(t); // LSP for TimeType, more generic
> }
>
> I vote for 2 x time_limited_wait.

duration and absolute_time will have distinct types. In Boost at the moment,
for boost::condition_variable, duration is anything that implements the Boost
Date-Time duration concept, such as boost::posix_time::milliseconds, and
absolute_time is boost::system_time.

However, even though distinct overloads will be called, this is not
necessarily desirable, as the semantics are distinct. The members of the LWG
are discussing renaming condition_variable::timed_wait to have distinct names
for the duration and absolute time overloads in order to ensure that the user
has absolute clarity of intent: wait_for(absolute_time) or
wait_until(duration) won't compile.

Anthony
--
Anthony Williams            | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Re view Request: future library (N2561/Williams version)

by Peter Dimov-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Anthony Williams:

> One way to do this is have the pool use packaged_tasks internally, and set
> a
> wait callback which is invoked when a thread waits on a future from a pool
> task. When the callback is invoked by the waiting thread (as part of the
> call
> to wait()), if that waiting thread is a pool thread, it can proceed as
> above.

It actually doesn't matter whether the waiting thread is a pool thread or
not. If the task hasn't been scheduled, it can be "stolen" and executed
synchronously from within the wait().

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Re view Request: future library (N2561/Williams version)

by Anthony Williams-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

"Peter Dimov" <pdimov@...> writes:

> Anthony Williams:
>
>> One way to do this is have the pool use packaged_tasks internally, and set
>> a
>> wait callback which is invoked when a thread waits on a future from a pool
>> task. When the callback is invoked by the waiting thread (as part of the
>> call
>> to wait()), if that waiting thread is a pool thread, it can proceed as
>> above.
>
> It actually doesn't matter whether the waiting thread is a pool thread or
> not. If the task hasn't been scheduled, it can be "stolen" and executed
> synchronously from within the wait().

Yes, you could do that. I'm not convinced it's necessarily a good idea,
though. Different threads potentially have different priorities or access
permissions. Also, thread interruption will behave differently: in my
prototype implementation, future::wait() is an interruption point. If a call
to wait() stole a task from a thread pool, interrupting the thread would
instead interrupt the task, which is not necessarily what was intended, as
this may have consequences for other threads waiting on that task.

Anthony
--
Anthony Williams            | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Re view Request: future library (N2561/Williams version)

by Johan Torp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Anthony Williams-3 wrote:
Suppose you're using a thread pool to provide a parallel version of
quick-sort. The easiest way to do that is to partition the values into those
less than and those not-less-than the chosen pivot (as you would for a
single-threaded version), and submit tasks to the thread pool to sort each
half and then waits for them to finish. This doubles the number of tasks with
each level of recursion. At some point the number of tasks will exceed the
number of threads in the pool, in which case you have some tasks waiting on
others that have been submitted to the pool but not yet scheduled.

If you can arrange for the implementation to identify this scenario as it
happens, and thus schedule the task being waited for to run on the waiting
thread, you can achieve greater thread reuse within the pool, and reduce the
number of blocked threads.

One way to do this is have the pool use packaged_tasks internally, and set a
wait callback which is invoked when a thread waits on a future from a pool
task. When the callback is invoked by the waiting thread (as part of the call
to wait()), if that waiting thread is a pool thread, it can proceed as
above. If not, then it might arrange to schedule the waited-for task next, or
just do nothing: the task will get its turn in the end.
I misunderstood - I thought set_wait_callback was Gaskill's proposed callback when a future was ready.

If I understand you correctly this use case is as follows;
Each future correlates to an unfinished task.
A. When a worker thread calls wait(), instead of/prior to blocking it might perform another task
B. By detecting when client/non-worker threads are waiting we can use that information to serve them faster.

A seems very dangerous. The worker thread has a stack associated with the task it is carrying out. If the thread crashes or an exception is thrown, only the current task is affected. If it should carry out another task [task2] on top of the first task [task1], task2 crashing would destroy task1 too. Also, we could get a problem with too deep stack nesting if the same thread starts working on more and more tasks.

B might be useful. It can't detect waiting by periodic is_ready-polling - which with todays interface is needed to wait for more than one future. Rather than implicitly trying to guess client threads' needs wouldn't it be better to either:
- Let the thread-pool be a predictable FIFO queue. Trust client code to do the scheduling and not submit too many tasks at the same time.
- Open up the pool interface and let users control some kind of prioritization or scheduling

I'm probably misunderstanding something here.


Anthony Williams-3 wrote:
Waiting for one of a number of tasks is an important use case. I'm not sure
how best to handle it. I've seen people talk about "future_or" and "f1 || f2",
but I'm not sure if that's definitely the way to go.
I think we should allow waiting on a dynamically changing number of futures. Operators are poorly suited for this because they require function recursion. Maybe some kind of future container with wait_all() and wait_any() functions. My biggest question is how this will map to condition_variables. Also, could this facility be some layer below futures which can be reused?

Dependency deduction and lazy return value composition functionality - like operators - should probably be built on top of the dynamic waiting facility.

Anthony Williams-3 wrote:
However, even though distinct overloads will be called, this is not
necessarily desirable, as the semantics are distinct.
In what way are the semantics different?

Anthony Williams-3 wrote:
The members of the LWG are discussing renaming condition_variable::timed_wait to have distinct names
for the duration and absolute time overloads in order to ensure that the user
has absolute clarity of intent: wait_for(absolute_time) or
wait_until(duration) won't compile.
To be extra clear, I'll repeat myself: This will complicate writing parallel algorithms which works generically with any time type. For both library vendors and users.

My 5 cents is still that 2 x time_limited_wait is clear and readable enough but it's no strong opinion. For good or bad you are forcing users to supply their intent twice - by both argument type and method name. Is this a general strategy for the standard library?


Best Regards, Johan

Re: Re view Request: future library (N2561/Williams version)

by Anthony Williams-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Johan Torp <johan.torp@...> writes:

> Anthony Williams-3 wrote:
> I misunderstood - I thought set_wait_callback was Gaskill's proposed
> callback when a future was ready.

No problem.

> If I understand you correctly this use case is as follows;
> Each future correlates to an unfinished task.
> A. When a worker thread calls wait(), instead of/prior to blocking it might
> perform another task
> B. By detecting when client/non-worker threads are waiting we can use that
> information to serve them faster.

Yes.

> A seems very dangerous. The worker thread has a stack associated with the
> task it is carrying out. If the thread crashes or an exception is thrown,
> only the current task is affected. If it should carry out another task
> [task2] on top of the first task [task1], task2 crashing would destroy task1
> too. Also, we could get a problem with too deep stack nesting if the same
> thread starts working on more and more tasks.

If the thread "crashes", you've got a serious bug: all bets are off. It
doesn't matter whether that's the same thread that's performing another task
or not.

If the task throws an exception, I expect this to be swallowed by the
task-launching code, and get stored in the future corresponding to that
task. This therefore will not affect the original waiting task.

Stack overflow is potentially a real problem. If a thread pool implementation
decides to do such task nesting, it needs to ensure the stack is sufficiently
large to handle it. For example, if you're going to allow N nested tasks, the
stack for that pool thread ought to be N times larger than the stack for a
single task.

> B might be useful. It can't detect waiting by periodic is_ready-polling -
> which with todays interface is needed to wait for more than one future.

I would use timed_wait() calls when waiting for more than one future: doing a
busy-wait with is_ready just consumes CPU time which would be better spent
actually doing the work that will set the futures to ready, and timed_wait is
more expressive than sleep:

void wait_for_either(jss::unique_future<int>& a,jss::unique_future<int>& b)
{
    if(a.is_ready() || b.is_ready())
    {
        return true;
    }
    while(!a.timed_wait(boost::posix_time::milliseconds(1)) &&
          !b.timed_wait(boost::posix_time::milliseconds(1)));
}

This will trigger the callback.

> Rather than implicitly trying to guess client threads' needs wouldn't it be
> better to either:
> - Let the thread-pool be a predictable FIFO queue. Trust client code to do
> the scheduling and not submit too many tasks at the same time.

That's not appropriate for situations where a task on the pool can submit more
tasks to the same pool, as in my quicksort example.

> - Open up the pool interface and let users control some kind of
> prioritization or scheduling

Allowing callbacks doesn't preclude this option.

> I'm probably misunderstanding something here.

There are many ways of scheduling threads in a thread pool, not all of which
are suitable for all circumstances. Providing set_wait_callback gives the
writer of the thread pool flexibility to choose the most appropriate model for
the circumstances he is trying to handle.

> Anthony Williams-3 wrote:
>>
>> Waiting for one of a number of tasks is an important use case. I'm not
>> sure
>> how best to handle it. I've seen people talk about "future_or" and "f1 ||
>> f2",
>> but I'm not sure if that's definitely the way to go.
>>
>
> I think we should allow waiting on a dynamically changing number of futures.
> Operators are poorly suited for this because they require function
> recursion. Maybe some kind of future container with wait_all() and
> wait_any() functions. My biggest question is how this will map to
> condition_variables. Also, could this facility be some layer below futures
> which can be reused?

My wait_for_either above could easily be extended to a dynamic set, and to do
wait_for_both instead.

Condition variables are more complicated, since they don't inherently support
wait-for-any or wait-for-all operations, and every wake from a timed_wait call
removes the thread from the waitset for that cv. To make it work, you would
have to supply all the predicates associated with each cv, and all the
associated mutexes. I think I'd rather just use futures.

> Dependency deduction and lazy return value composition functionality - like
> operators - should probably be built on top of the dynamic waiting facility.

It would be relatively simple to build an operator on top of wait_for_either().

> Anthony Williams-3 wrote:
>>
>> However, even though distinct overloads will be called, this is not
>> necessarily desirable, as the semantics are distinct.
>>
>
> In what way are the semantics different?

timed_wait(duration) waits for a specified amount of time to
elapse. timed_wait(absolute_time) waits until the clock reads the specified
time. This can be important if you're using a cv in a loop:

boost::mutex m;
boost::condition_variable cv;
bool done=false;

template<typename Duration>
bool wait_with_background_processing(Duration d)
{
    boost::system_time timeout=boost::get_system_time()+d;
    boost::unique_lock<boost::mutex> lk(m);
    while(!done)
    {
        if(!cv.timed_wait(d)) // oops, meant timeout
        {
            return false;
        }
        lk.unlock();
        do_background_processing();
        lk.lock();
    }
}

This code will compile and run, but will wait up to the specified duration
every time round the loop rather than waiting only the specified duration in
total. By giving the duration and absolute-time overloads different names, you
can avoid this bug.

> Anthony Williams-3 wrote:
>>
>> The members of the LWG are discussing renaming
>> condition_variable::timed_wait to have distinct names
>> for the duration and absolute time overloads in order to ensure that the
>> user
>> has absolute clarity of intent: wait_for(absolute_time) or
>> wait_until(duration) won't compile.
>>
>
> To be extra clear, I'll repeat myself: This will complicate writing parallel
> algorithms which works generically with any time type. For both library
> vendors and users.

Generic code needs to know whether it's got a duration or an absolute time, so
this is not an issue, IMHO.

> My 5 cents is still that 2 x time_limited_wait is clear and readable enough
> but it's no strong opinion. For good or bad you are forcing users to supply
> their intent twice - by both argument type and method name. Is this a
> general strategy for the standard library?

This is an important strategy with condition variables, and it is probably
sensible to do the same elsewhere in the standard library for consistency.

Anthony
--
Anthony Williams            | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Re view Request: future library (N2561/Williams version)

by Vicente Botet Escriba :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

----- Original Message -----
From: "Anthony Williams" <anthony_w.geo@...>
To: <boost@...>
Sent: Monday, May 12, 2008 12:52 PM
Subject: Re: [boost] Re view Request: future library (N2561/Williams
version)

> duration and absolute_time will have distinct types. In Boost at the
> moment,
> for boost::condition_variable, duration is anything that implements the
> Boost
> Date-Time duration concept, such as boost::posix_time::milliseconds, and
> absolute_time is boost::system_time.

Please could you add this to the documentation of the Boost.Thread
(duration_type is anything that implements the Boost Date-Time duration
concept). I have no seen it on the documentation. The same should be true
for the other uses of dureation_type as template parameter. I think that it
becomes urgent to solve the time versus duration concepts usable on real
time applications and doispose of specific models.

template<typename lock_type,typename duration_type> bool
timed_wait(lock_type& lock,duration_type const& rel_time)
Effects:
Atomically call lock.unlock() and blocks the current thread. The thread will
unblock when notified by a call to this->notify_one() or this->notify_all(),
after the period of time indicated by the rel_time argument has elapsed, or
spuriously. When the thread is unblocked (for whatever reason), the lock is
reacquired by invoking lock.lock() before the call to wait returns. The lock
is also reacquired by invoking lock.lock() if the function exits with an
exception.

Best,
icente

_____________________
Vicente Juan Botet Escriba


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Review Request: future library : what does future of references exactly means?

by Vicente Botet Escriba :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

----- Original Message -----
From: "Johan Torp" <johan.torp@...>
To: <boost@...>
Sent: Monday, May 12, 2008 12:14 PM
Subject: Re: [boost] Re view Request: future library (N2561/Williams
version)


> I thought the most common use case for futures was the active object
> pattern. We should all try to agree what use cases/design patterns/higher
> level abstractions are most important and which we want to support. IMHO,
> this should be top priority for the "future ambition". Even though no
> higher
> level abstractions built on futures will make it to C++0x or boost anytime
> soon, it's important that the future interface needn't change to support
> them in the - future :)

I don't know if the most common use case is the active object pattern, I use
it every time I call a functions whic could finish or not depending on its
internals. Some times the function sould wait on some messages and then the
best is to return a future. But the function can also finish on the same
thread if it don't needs external interaction.
The client could later on wait in the future (active) or attach a callback
to be called when the future is ready (reaction). For example:

{
    // ...
    future<T> f = call_somme_fct();
    // ...
    // when the result is needed either wait by using it or
    if (!f) // attach some callback and change the intenal state
    else // continue
    // ...
}

I agree with you that the best test for the future interface is to show some
good usages in the tutorial and examples of the library. The threadpool
library could be one, but not the only one.

Imagine now we had a function which returs a value and had an out parameter
(maybe by reference)

Result f(InOut& ref);

Now we want to refactor this function (either because the new implementation
will introduce an IO wait, or because the old blocking  implementation could
not be supported. Which should be the interface of the new function. The
first thing could be to try with

    future<Result> f(InOut& ref);

but nothing forbids the caller to use the ref parameter before the operation
has completed and which could be invalid. If we want consistency what we
would need is something like

    future<Result> f(future<InOut&>& ref);

IMO this do not works in any proposal?
Do we need future to works with in/out references?

Yet another example
    future<Out&> f();

Note that future<Out&> and future<InOut&> should not mean the same. Do we
need two future of reference classes? future<InOut&> will need a constructor
    future<InOut&>(InOut&),
but the assocaited promise should copy the value when doint the set_value.

Any thought? Has all this a sense or I'm completly lost?

This example was there only to introdude other use cases, and in particular
future of reference types or pointer types. If you have a better choice for
the f function do not hesitate.

Anthony, sorry for short cut (futures instead of unique_future or
shared_future). In order to be coherent with the thread library
(mutex/shared_mutex), should't unique_future be named future?

Vicente


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Review Request: future library : what does future of references exactly means?

by Anthony Williams-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

"vicente.botet" <vicente.botet@...> writes:

> Imagine now we had a function which returs a value and had an out parameter
> (maybe by reference)
>
> Result f(InOut& ref);
>
> Now we want to refactor this function (either because the new implementation
> will introduce an IO wait, or because the old blocking  implementation could
> not be supported. Which should be the interface of the new function. The
> first thing could be to try with
>
>     future<Result> f(InOut& ref);
>
> but nothing forbids the caller to use the ref parameter before the operation
> has completed and which could be invalid. If we want consistency what we
> would need is something like
>
>     future<Result> f(future<InOut&>& ref);
>
> IMO this do not works in any proposal?

You can write it with my proposal, but I'm not sure it means what you intend,
given what you write below.

> Do we need future to works with in/out references?
>
> Yet another example
>     future<Out&> f();
>
> Note that future<Out&> and future<InOut&> should not mean the same. Do we
> need two future of reference classes? future<InOut&> will need a constructor
>     future<InOut&>(InOut&),
> but the assocaited promise should copy the value when doint the set_value.

If the promise associated with your future<InOut&> should copy the value, then
what you want is a future<InOut>. If you had a future<InOut&>(InOut&)
constructor, then you could /still/ use the original InOut& before the future
had returned, just as if you passed a plain reference to the function.

With my (updated) proposal, unique_future<T>::get() returns an
rvalue-reference, so you could move/copy this into the InOut value you intend
to use, or you could use shared_future<T>, where get() returns a const
reference.

> Anthony, sorry for short cut (futures instead of unique_future or
> shared_future). In order to be coherent with the thread library
> (mutex/shared_mutex), should't unique_future be named future?

unique_future/shared_future is by analogy to unique_ptr/shared_ptr, which I
think is a closer match than mutex/shared_mutex.

Anthony
--
Anthony Williams            | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Re view Request: future library (N2561/Williams version)

by Anthony Williams-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

"vicente.botet" <vicente.botet@...> writes:

> ----- Original Message -----
> From: "Anthony Williams" <anthony_w.geo@...>
> To: <boost@...>
> Sent: Monday, May 12, 2008 12:52 PM
> Subject: Re: [boost] Re view Request: future library (N2561/Williams
> version)
>
>> duration and absolute_time will have distinct types. In Boost at the
>> moment,
>> for boost::condition_variable, duration is anything that implements the
>> Boost
>> Date-Time duration concept, such as boost::posix_time::milliseconds, and
>> absolute_time is boost::system_time.
>
> Please could you add this to the documentation of the Boost.Thread
> (duration_type is anything that implements the Boost Date-Time duration
> concept). I have no seen it on the documentation. The same should be true
> for the other uses of dureation_type as template parameter. I think that it
> becomes urgent to solve the time versus duration concepts usable on real
> time applications and doispose of specific models.

It's on my list.

Anthony
--
Anthony Williams            | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Re view Request: future library (N2561/Williams version)

by Johan Torp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Anthony Williams-3 wrote:
If the thread "crashes", you've got a serious bug: all bets are off. It
doesn't matter whether that's the same thread that's performing another task
or not.
I agree that something is seriously wrong and that we perhaps don't need to handle things gracefully. But if the threading API allows us to detect "crashing" threads somehow, we could avoid spreading a thread-local problem to the whole process. The client thread could even be notified with a thread_crash exception set in the future. I'm haven't had time to read up on what possibilities the C++0x threading API will supply here, but I suppose you know. Maybe there isn't even a notion of a thread crashing without crashing the process.

At the very least, I see a value in not behaving worst than if the associated client thread would have spawned it's own worker thread. That is:
  std::launch_in_pool(&crashing_function);
should not behave worse than
  std::thread t(&crashing_function);

Anthony Williams-3 wrote:
> B might be useful. It can't detect waiting by periodic is_ready-polling -
> which with todays interface is needed to wait for more than one future.

I would use timed_wait() calls when waiting for more than one future: doing a
busy-wait with is_ready just consumes CPU time which would be better spent
actually doing the work that will set the futures to ready, and timed_wait is
more expressive than sleep:

void wait_for_either(jss::unique_future<int>& a,jss::unique_future<int>& b)
{
    if(a.is_ready() || b.is_ready())
    {
        return true;
    }
    while(!a.timed_wait(boost::posix_time::milliseconds(1)) &&
          !b.timed_wait(boost::posix_time::milliseconds(1)));
}
It could as well have been implemented by:

    while (!a.is_ready() || !b.is_ready())
    {
        a.timed_wait(boost::posix_time::milliseconds(1));
    }

You can't detect that b is needed here. I would not implement dynamic wait by timed_waiting on every single future, one at a time. Rather i would have done something like:

void wait_for_any(const vector<future<void>>& futures)
{
  while (1)
  {
    for (...f in futures...) if (f.is_ready()) return;
    sleep(10ms);
  }
}

Anthony Williams-3 wrote:
> - Let the thread-pool be a predictable FIFO queue. Trust client code to do
> the scheduling and not submit too many tasks at the same time.

That's not appropriate for situations where a task on the pool can submit more
tasks to the same pool, as in my quicksort example.
Ah - I knew I missed something. Agreed, child tasks should be prioritized. But that mechanism could be kept internal in the thread pool.

Anthony Williams-3 wrote:
My wait_for_either above could easily be extended to a dynamic set, and to do
wait_for_both instead.
Still you don't really wait for more than one future at a time. Both yours and mine suggestion above are depressingly inefficient if you were to wait on 1000s of futures simultaneously. I don't know if this will be a real use case or not. If the many core prediction comes true and we get 1000s of cores, it might very well be.  

Anthony Williams-3 wrote:
> My 5 cents is still that 2 x time_limited_wait is clear and readable enough
> but it's no strong opinion. For good or bad you are forcing users to supply
> their intent twice - by both argument type and method name. Is this a
> general strategy for the standard library?

This is an important strategy with condition variables, and it is probably
sensible to do the same elsewhere in the standard library for consistency.
I understand your point, even though I'm not sure it's the best strategy. Rather than arguing with more experienced people, I'll adopt whatever public code I write to this.


Johan

Re: Review Request: future library : what does future of references exactly means?

by Johan Torp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

vicente.botet wrote:
Imagine now we had a function which returs a value and had an out parameter
(maybe by reference)

Result f(InOut& ref);

Now we want to refactor this function (either because the new implementation
will introduce an IO wait, or because the old blocking  implementation could
not be supported. Which should be the interface of the new function. The
first thing could be to try with

    future<Result> f(InOut& ref);

but nothing forbids the caller to use the ref parameter before the operation
has completed and which could be invalid. If we want consistency what we
would need is something like

    future<Result> f(future<InOut&>& ref);
Firstly, this is a dangerous design. The calling thread must keep the reference alive until the future is ready - no matter what. For instance, what if it's owner thread tells it to terminate?

Secondly, you can't prohibit the calling thread to access it's original reference. So the problem isn't really solved.

Presently, I haven't seen any use cases which would motivate reference support for futures. Not allowing references is a safety net in it's own right.

vicente.botet wrote:
Yet another example
    future<Out&> f();
This is also very dangerous, the promise-fulfilling thread must guarantee that the reference is valid until program termination as it can't detect when the future dies. Even if it could detect future destruction, it would be a strange design. Shared_ptrs or some kind of moving should be applied here.

Johan

Re: Review Request: future library : what does future ofreferences exactly means?

by Vicente Botet Escriba :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

----- Original Message -----
From: "Anthony Williams" <anthony_w.geo@...>
To: <boost@...>
Sent: Tuesday, May 13, 2008 8:51 AM
Subject: Re: [boost] Review Request: future library : what does future
ofreferences exactly means?


> "vicente.botet" <vicente.botet@...> writes:
>
>> Imagine now we had a function which returs a value and had an out
>> parameter
>> (maybe by reference)
>>
>> Result f(InOut& ref);
>>
>> Now we want to refactor this function (either because the new
>> implementation
>> will introduce an IO wait, or because the old blocking  implementation
>> could
>> not be supported. Which should be the interface of the new function. The
>> first thing could be to try with
>>
>>     future<Result> f(InOut& ref);
>>
>> but nothing forbids the caller to use the ref parameter before the
>> operation
>> has completed and which could be invalid. If we want consistency what we
>> would need is something like
>>
>>     future<Result> f(future<InOut&>& ref);
>>
>> IMO this do not works in any proposal?
>
> You can write it with my proposal, but I'm not sure it means what you
> intend,
> given what you write below.
>
>> Do we need future to works with in/out references?
>>
>> Yet another example
>>     future<Out&> f();
>>
>> Note that future<Out&> and future<InOut&> should not mean the same. Do we
>> need two future of reference classes? future<InOut&> will need a
>> constructor
>>     future<InOut&>(InOut&),
>> but the assocaited promise should copy the value when doint the
>> set_value.
>
> If the promise associated with your future<InOut&> should copy the value,
> then
> what you want is a future<InOut>. If you had a future<InOut&>(InOut&)
> constructor, then you could /still/ use the original InOut& before the
> future
> had returned, just as if you passed a plain reference to the function.
>
> With my (updated) proposal, unique_future<T>::get() returns an
> rvalue-reference, so you could move/copy this into the InOut value you
> intend
> to use, or you could use shared_future<T>, where get() returns a const
> reference.

Well let me come back to my initial example. Supose that I had
    Result f(InOut& ref);
    // ...
        {
            InOut v=0;
            // ...
            v = 13;
            Result r = f(v);
            // ...     use r or v;
            g(r, v);
            v = 15;
        }

Do you mean that the following works with your proposal?

    unique_future<Result> f(shared_future<InOut>& ref);
    // ...
        {
            shared_future<InOut> v; v->get()=0;
            // ...
            v->get() = 13;
            unique_future<Result> r = f(v);
            // ... use r or v;
            g(r->get(), v->get());
            v->get() = 15;
        }


>> Anthony, sorry for short cut (futures instead of unique_future or
>> shared_future). In order to be coherent with the thread library
>> (mutex/shared_mutex), should't unique_future be named future?
>
> unique_future/shared_future is by analogy to unique_ptr/shared_ptr, which
> I
> think is a closer match than mutex/shared_mutex.

OK. I understand

Vicente

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Re: Re view Request: future library : what does future of references exactly means?

by Vicente Botet Escriba :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


---------------------------
Vicente Juan Botet Escriba
----- Original Message -----
From: "Johan Torp" <johan.torp@...>
To: <boost@...>
Sent: Tuesday, May 13, 2008 11:42 AM
Subject: Re: [boost] Re view Request: future library : what does future of
references exactly means?


>
>
> vicente.botet wrote:
>>
>> Imagine now we had a function which returs a value and had an out
>> parameter
>> (maybe by reference)
>>
>> Result f(InOut& ref);
>>
>> Now we want to refactor this function (either because the new
>> implementation
>> will introduce an IO wait, or because the old blocking  implementation
>> could
>> not be supported. Which should be the interface of the new function. The
>> first thing could be to try with
>>
>>     future<Result> f(InOut& ref);
>>
>> but nothing forbids the caller to use the ref parameter before the
>> operation
>> has completed and which could be invalid. If we want consistency what we
>> would need is something like
>>
>>     future<Result> f(future<InOut&>& ref);
>>
>
> Firstly, this is a dangerous design. The calling thread must keep the
> reference alive until the future is ready - no matter what. For instance,
> what if it's owner thread tells it to terminate?

What do you propose instead? What do you think of
     future<Result> f(cosnt InOut& in, future<InOut>& out);

    future<InOut> fv;
    r= f(v,  fv)
    v = fv.get();


> Secondly, you can't prohibit the calling thread to access it's original
> reference. So the problem isn't really solved.

You are right, the problem is not solved.

> Presently, I haven't seen any use cases which would motivate reference
> support for futures. Not allowing references is a safety net in it's own
> right.


> vicente.botet wrote:
>>
>> Yet another example
>>     future<Out&> f();
>>
>
> This is also very dangerous, the promise-fulfilling thread must guarantee
> that the reference is valid until program termination as it can't detect
> when the future dies. Even if it could detect future destruction, it would
> be a strange design. Shared_ptrs or some kind of moving should be applied
> here.

This is not more dangerous that
     Out& f();

We know how dangerous it is and we use every time. This reference point
usualy to a member object, and the object can be deleted.

Vicente


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
< Prev | 1 - 2 - 3 - 4 - 5 - 6 | Next >