Topic: Defect Report: packaged_task is too strongly typed


Author: Andy Lutomirski <luto@amacapital.net>
Date: Sun, 4 Nov 2012 13:42:00 CST
Raw View
packaged_task is almost perfect for use in custom thread pools, like this:

packaged_task<int> task([] { /* something */ });
future<int> result;
threadpool.submit(task);

// later on
int x = result.get();

This doesn't work well, though: the threadpool.submit() function would
like to accept packaged_task<T> for any T -- the only packaged_task
functionality that depends on the return type (as opposed to the
parameter type) is get_future, and get_future can only be called once.

This means that the submit function would need to be a template and use
some unnecessarily complicated trick to deal with different
packaged_task types.

Any number of fixes are possible.  For example, packaged_task<void,
ArgTypes...> could have a member

template<typename F>
static pair<future<R>, packaged_task<void, ArgTypes...>>
create_void(F&& f);

Alternatively, a packaged_task that has already had get_future called
could be moveable to packaged_task<void, ArgTypes...>.

A third possibility would be for packaged_task<R, ArgTypes...> to derive
from a new template that depends only on ArgTypes.  This could be
awkward and would be more likely to have backwards compatibility issues.

(I would guess the cause of this issue is that packaged_task is trying
to have a similar interface to promise, where the get_future interface
is harmless.)


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Sun, 4 Nov 2012 21:16:35 CST
Raw View

Am 04.11.2012 20:42, schrieb Andy Lutomirski:
>
> packaged_task is almost perfect for use in custom thread pools, like this:
>
> packaged_task<int> task([] { /* something */ });

This example cannot work, because packaged_task can only be
instantiated with a function type, but 'int' isn't such a beast.

> future<int> result;
> threadpool.submit(task);
>
> // later on
> int x = result.get();
>
> This doesn't work well, though: the threadpool.submit() function would
> like to accept packaged_task<T> for any T -- the only packaged_task
> functionality that depends on the return type (as opposed to the
> parameter type) is get_future, and get_future can only be called once.
>
> This means that the submit function would need to be a template and use
> some unnecessarily complicated trick to deal with different
> packaged_task types.

I'm unconvinced that what you are describing here really is a defect.

It sounds as if you say that for similar reasons std::function
shouldn't be a template that depends on a function type. The current
design of packaged_task makes perfect sense, because a packaged_task
represents a type that wraps any function-like object (very similar to
std::function) and it also allows to call invoke this callable via a
corresponding set of functions:

void operator()(ArgTypes... );
void make_ready_at_thread_exit(ArgTypes...);

Obviously these depend on the remaining parts of the signature. So
this seems to invalidate your claims above.

> Any number of fixes are possible.  For example, packaged_task<void,
> ArgTypes...>

Do you mean packaged_task<void(ArgTypes...)> ?

> could have a member
> template<typename F>
> static pair<future<R>, packaged_task<void, ArgTypes...>>
> create_void(F&& f);

I don't see how this would work, if either the return type or the
argument types are missing.

HTH & Greetings from Bremen,

Daniel Kr   gler



--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Andy Lutomirski <luto@amacapital.net>
Date: Tue, 13 Nov 2012 12:39:45 -0800 (PST)
Raw View
[resend, with cc this time -- my last try got lost, and the usual
channels for tracking down lost articles aren't working]

This may be considerably more clear once I fix the obvious errors.  I
misread the signature of packaged_task.


On 11/04/2012 07:16 PM, Daniel Kr=FCgler wrote:
>
>
> Am 04.11.2012 20:42, schrieb Andy Lutomirski:
>>
>> packaged_task is almost perfect for use in custom thread pools, like
>> this:
>>
>> packaged_task<int> task([] { /* something */ });
>
> This example cannot work, because packaged_task can only be
> instantiated with a function type, but 'int' isn't such a beast.

This should be:

packaged_task<int ()> task([] { /* something */ });
future<int> result = task.get_future();
threadpool.submit(task);

// later on
int x = result.get();


>>
>> This doesn't work well, though: the threadpool.submit() function would
>> like to accept packaged_task<T> for any T -- the only packaged_task
>> functionality that depends on the return type (as opposed to the
>> parameter type) is get_future, and get_future can only be called once.
>>
>> This means that the submit function would need to be a template and use
>> some unnecessarily complicated trick to deal with different
>> packaged_task types.
>
> I'm unconvinced that what you are describing here really is a defect.
>
> It sounds as if you say that for similar reasons std::function
> shouldn't be a template that depends on a function type. The current
> design of packaged_task makes perfect sense, because a packaged_task
> represents a type that wraps any function-like object (very similar to
> std::function) and it also allows to call invoke this callable via a
> corresponding set of functions:
>
> void operator()(ArgTypes... );
> void make_ready_at_thread_exit(ArgTypes...);
>
> Obviously these depend on the remaining parts of the signature. So
> this seems to invalidate your claims above.

std::function, when called, returns the value that the wrapped object
returns, so its operator()'s return type depends on the function's
return type.

packaged_task's call operator returns void.  It should be possible to
invoke it without depending on the wrapped function's return type.

>
>> Any number of fixes are possible.  For example, packaged_task<void,
>> ArgTypes...>
>
> Do you mean packaged_task<void(ArgTypes...)> ?

Yes.

>
>> could have a member
>> template<typename F>
>> static pair<future<R>, packaged_task<void, ArgTypes...>>
>> create_void(F&& f);
>

template<typename F>
static pair<future<R>, packaged_task<void (ArgTypes...)>>
create_void(F&& f);

> I don't see how this would work, if either the return type or the
> argument types are missing.

Here's a full example:

#include <future>
#include <utility>

using namespace std;

// SubmitToThreadpool does not (and cannot) care about
// the return type of task.
void SubmitToThreadpool(packaged_task<void ()> &&task)
{
  // In real code, this would involve threads.
  task();
}

int main()
{
  packaged_task<int ()> task([]{ return 1; });
  auto result = task.get_future();

  SubmitToThreadpool(move(task));  // Does not compile

  if (result.get() != 1)
    abort();

  return 0;
}

It will compile and work if you change void to int in
SubmitToThreadpool.  (If using gcc on linux, you'll need to compile with
-pthread or it blows up.  I'm not sure if this counts as a bug.)
There should be a way to generate a paired future<int> and a
packaged_task<void ()> (or some equivalent object).

--Andy


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Wed, 21 Nov 2012 11:23:33 -0800 (PST)
Raw View
On 2012-11-13 21:39, Andy Lutomirski wrote:
> On 11/04/2012 07:16 PM, Daniel Kr=FCgler wrote:
>>> This doesn't work well, though: the threadpool.submit() function would
>>> like to accept packaged_task<T> for any T -- the only packaged_task
>>> functionality that depends on the return type (as opposed to the
>>> parameter type) is get_future, and get_future can only be called once.
>>>
>>> This means that the submit function would need to be a template and use
>>> some unnecessarily complicated trick to deal with different
>>> packaged_task types.
>>
>> I'm unconvinced that what you are describing here really is a defect.
>>
>> It sounds as if you say that for similar reasons std::function
>> shouldn't be a template that depends on a function type. The current
>> design of packaged_task makes perfect sense, because a packaged_task
>> represents a type that wraps any function-like object (very similar to
>> std::function) and it also allows to call invoke this callable via a
>> corresponding set of functions:
>>
>> void operator()(ArgTypes... );
>> void make_ready_at_thread_exit(ArgTypes...);
>>
>> Obviously these depend on the remaining parts of the signature. So
>> this seems to invalidate your claims above.
>
> std::function, when called, returns the value that the wrapped object
> returns, so its operator()'s return type depends on the function's
> return type.
>
> packaged_task's call operator returns void.  It should be possible to
> invoke it without depending on the wrapped function's return type.

I certainly agree, but my arguments were related to the fact, that *all*
types mentioned in the packaged_task template signature are part of
public API and thus are obviously adequate. For some use-cases (like
those you describe), parts of this type information can be superfluous,
but that fact alone is not a reason for a defect, because you can easily
type-erase such occurrences.

>>> could have a member
>>> template<typename F>
>>> static pair<future<R>, packaged_task<void, ArgTypes...>>
>>> create_void(F&& f);
>>
>
> template<typename F>
> static pair<future<R>, packaged_task<void (ArgTypes...)>>
> create_void(F&& f);

I guess such an extension *could* be added, but I don't see how the lack
of these can be considered as a defect. If you think that such an
addition should be standardized, I suggest to create a proposal
following the descriptions of

http://isocpp.org/std/submit-a-proposal

to add such a feature.

> Here's a full example:
>
> #include <future>
> #include <utility>
>
> using namespace std;
>
> // SubmitToThreadpool does not (and cannot) care about
> // the return type of task.
> void SubmitToThreadpool(packaged_task<void ()> &&task)
> {
>    // In real code, this would involve threads.
>    task();
> }
>
> int main()
> {
>    packaged_task<int ()> task([]{ return 1; });
>    auto result = task.get_future();
>
>    SubmitToThreadpool(move(task));  // Does not compile
>
>    if (result.get() != 1)
>      abort();
>
>    return 0;
> }
>
> It will compile and work if you change void to int in
> SubmitToThreadpool.  (If using gcc on linux, you'll need to compile with
> -pthread or it blows up.  I'm not sure if this counts as a bug.)
> There should be a way to generate a paired future<int> and a
> packaged_task<void ()> (or some equivalent object).

I understand that this example does not compile, but I believe there are
simple adapter techniques to make this happen without changing the
library specification of packaged_task for the moment. If you think that
your interface extension (or other means that you have mentioned) should
be standardized, I suggest to submit a corresponding proposal as
described by

http://isocpp.org/std/submit-a-proposal

HTH & Greetings from Bremen,

Daniel Kr   gler



--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]




Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Wed, 21 Nov 2012 11:27:54 -0800 (PST)
Raw View
[3nd attempt after 2 days]

[ Moderator's note: The servers for several newsgroups were broken for 3 days. Fixed now. ]

On 2012-11-13 21:39, Andy Lutomirski wrote:
> On 11/04/2012 07:16 PM, Daniel Kr=FCgler wrote:
>>> This doesn't work well, though: the threadpool.submit() function would
>>> like to accept packaged_task<T> for any T -- the only packaged_task
>>> functionality that depends on the return type (as opposed to the
>>> parameter type) is get_future, and get_future can only be called once.
>>>
>>> This means that the submit function would need to be a template and use
>>> some unnecessarily complicated trick to deal with different
>>> packaged_task types.
>>
>> I'm unconvinced that what you are describing here really is a defect.
>>
>> It sounds as if you say that for similar reasons std::function
>> shouldn't be a template that depends on a function type. The current
>> design of packaged_task makes perfect sense, because a packaged_task
>> represents a type that wraps any function-like object (very similar to
>> std::function) and it also allows to call invoke this callable via a
>> corresponding set of functions:
>>
>> void operator()(ArgTypes... );
>> void make_ready_at_thread_exit(ArgTypes...);
>>
>> Obviously these depend on the remaining parts of the signature. So
>> this seems to invalidate your claims above.
>
> std::function, when called, returns the value that the wrapped object
> returns, so its operator()'s return type depends on the function's
> return type.
>
> packaged_task's call operator returns void.  It should be possible to
> invoke it without depending on the wrapped function's return type.

I certainly agree, but my arguments were related to the fact, that *all*
types mentioned in the packaged_task template signature are part of
public API and thus are obviously adequate. For some use-cases (like
those you describe), parts of this type information can be superfluous,
but that fact alone is not a reason for a defect, because you can easily
type-erase such occurrences.

>>> could have a member
>>> template<typename F>
>>> static pair<future<R>, packaged_task<void, ArgTypes...>>
>>> create_void(F&& f);
>>
>
> template<typename F>
> static pair<future<R>, packaged_task<void (ArgTypes...)>>
> create_void(F&& f);

I guess such an extension *could* be added, but I don't see how the lack
of these can be considered as a defect. If you think that such an
addition should be standardized, I suggest to create a proposal
following the descriptions of

http://isocpp.org/std/submit-a-proposal

to add such a feature.

> Here's a full example:
>
> #include <future>
> #include <utility>
>
> using namespace std;
>
> // SubmitToThreadpool does not (and cannot) care about
> // the return type of task.
> void SubmitToThreadpool(packaged_task<void ()> &&task)
> {
>    // In real code, this would involve threads.
>    task();
> }
>
> int main()
> {
>    packaged_task<int ()> task([]{ return 1; });
>    auto result = task.get_future();
>
>    SubmitToThreadpool(move(task));  // Does not compile
>
>    if (result.get() != 1)
>      abort();
>
>    return 0;
> }
>
> It will compile and work if you change void to int in
> SubmitToThreadpool.  (If using gcc on linux, you'll need to compile with
> -pthread or it blows up.  I'm not sure if this counts as a bug.)
> There should be a way to generate a paired future<int> and a
> packaged_task<void ()> (or some equivalent object).

I understand that this example does not compile, but I believe there are
simple adapter techniques to make this happen without changing the
library specification of packaged_task for the moment. If you think that
your interface extension (or other means that you have mentioned) should
be standardized, I suggest to submit a corresponding proposal as
described by

http://isocpp.org/std/submit-a-proposal

HTH & Greetings from Bremen,

Daniel Kr   gler



--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]