mercredi 20 décembre 2017

std::promise external code, async cancellation

Suppose you have some external synchronous code you cannot modify, and you require it to run async but also require it to be cancellable. If the external code is blocking then I have two options.

A) Fool the user and let my async method return immediately on cancellation, well aware that the code is still running to completion somewhere.

B) Cancel execution

I would like to implement an interface for option B

namespace externallib {
std::uint64_t timeconsuming_operation()
{
    std::uint64_t count = 0;
    for (auto i = 0; i < 1E+10; ++i)
    {
        count++;
    }
    return count;
}
}




template <typename R>
struct async_operation
{

    struct CancelledOperationException
    {
        std::string what() const
        {
            return what_;
        }
    private:
        std::string what_{ "Operation was cancelled." };
    };

    template<typename Callable>
    async_operation(Callable&& c)
    {
        t_ = std::thread([this, c]()
        {
            promise_.set_value(c());  // <-- Does not care about cancel(), mostly because c() hasn't finished..
        });
    }


    std::future<R> get()
    {
        return promise_.get_future();
    }


    void cancel()
    {
        promise_.set_exception(std::make_exception_ptr(CancelledOperationException()));
    }

    ~async_operation()
    {
        if (t_.joinable())
            t_.join();
    }

private:
    std::thread t_;
    std::promise<R> promise_;
};

void foo()
{
    async_operation<std::uint64_t> op([]()
    {
        return externallib::timeconsuming_operation();
    });

    using namespace std::chrono_literals;
    std::this_thread::sleep_for(5s);

    op.cancel(); 
    op.get();
}

In the code above I cannot wrap my head around the limitation of external code being blocking, how, if at all, is it possible to cancel execution early?

Aucun commentaire:

Enregistrer un commentaire