C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::async_noexcept

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Tue, 7 Nov 2023 16:58:35 +0000
On Tue, Nov 7, Matthew Taylor wrote:
>
> Consider someone using this code. They call async_noexcept, get a future, and since nothing goes wrong
> they reasonably assume that the result of their call will be available in that future in due course. They may
> then go on to do X, Y, and Z and get to the other end of the program before calling get() on the future and
> only then learning that their initial async failed and they did all this extra work for nothing. Would your
> proposal mandate that as basic error handling, a user is also expected to do some investigation of their
> obtained future and try to deduce whether it failed without opening it up to try and get() it?


This is why the default return value is so important. I'm writing a
desktop PC program that spawns threads to communicate over RS232 ports
with Arduino microcontrollers. The spawned thread could fail to start
(which is very rare), or the thread might freeze up or fail in some
way. What I want from these worker threads is a UUID at the end of
their processing (i.e. a unique 128-Bit number), and so the entry
point to the thread has a prototype as follows:

    __uint128_t ProcessMicrocontroller(char const *str_port, long
unsigned baud);

And so then my code for spawning a thread looks like this:

    future<__uint128_t> myfuture;
    myfuture = async(launch::async, ProcessMicrocontroller,
"\\\\.\\COM27", 9600u);

I give the thread a set amount of time to get its job done, and then I do:

    myfuture.wait_for( std::chrono::seconds(3u) );

If this wait operation times out, or if the value of the future object
is 0 (corresponding to the 128-Bit UUID
00000000-0000-0000-0000-000000000000), then I abandon the future
object and start again with a new thread and a new future object. I'll
have a global container of future objects and allow it to get to N
size before my program tells the user "You need to close the program
and re-start it".

For this all to work, it's very important that there is a default
return value representing a failure, and in this case I've made it the
numeric value 0. If the thread entry point were to instead return a
bool, then the default return value could be false. Or if it returned
a stringview, then the default return value could be any stringview
whose size() is zero. If it returned a span, it could be an empty
span.

I checked just now, and you're right that std::promise::promise might
throw an exception (as might std::promise::get_future), and so I'll
have to spend a little more time on this. I'll try write code that has
a static-duration (or thread-local duration) promise and future
object, and then re-use these objects so that I know they won't throw
when they're needed -- I'm not actually sure if this will be possible
but I'll look into it and try.

Received on 2023-11-07 16:58:47