woder
woder

Reputation: 805

any elegant way to get c++20 coroutine handle to the outside?

we know that c++20 coroutine suspend and return caller after using co_await awaitable, if we want to resume this coroutine, the only way is to get the coroutine handle from awaitable object function void await_suspend(std::coroutine_handle<> cont) const and then use handle.resume() to resume coroutine, is there any way to get coroutine handle from the outside of coroutine or any better way to resume coroutine?

Upvotes: 1

Views: 1124

Answers (2)

woder
woder

Reputation: 805

well, I find a better way to resume coroutine from the caller by reference to c++23 std::generator, shown as below:

struct Result{
  //add
  Result(promise_type* obj):promise_type_ptr(obj){}
  //add
  void resume(){
    promise_type_ptr->resume();
  }

  struct promise_type {
    // mod
    Result get_return_object() { 
        return Reuslt(this);
    }
    
    // add
    void resume(){
        coroutine_handle<promise_type>::from_promise(*this).resume();
    }
    
    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
    void unhandled_exception() {}
    
    suspend_aways yield_value(){}
    void return_void() {}   
    Result return_value(const Result& res){ return res;}
  };
  
  // add
  promise_type *promise_type_ptr;
};

we can use coroutine_handle<promise_type>::from_promise(*this); to get coroutine handle from the promise_type object pointer, so we can create a function resume() in coroutine return result for caller, and use it as below

auto result = CoroutineFunction();
result.resume();

Upvotes: 3

Nicol Bolas
Nicol Bolas

Reputation: 473976

Broadly speaking, you should not want to get the handle from outside of the coroutine machinery. If you do, odds are good that you're not using coroutines in the way they're intended to be used.

The idea of coroutines as designed in C++20 is to be invisible. That is, from the perspective of code outside of the coroutines nobody should know that it is implemented as a coroutine. It is merely a function that returns some type which represents a value that can be obtained in the future; how it pulls this off is an implementation detail.

To "resume a coroutine" means to tell the future object returned by a coroutine function to produce the value. This should just be a regular API call into the future object. It is the future object which has access to the promise, and it is the promise which has access to the coroutine handle to resume it.

Also, unless the coroutine is a generator, the code which directly resumes the coroutine's execution is intended to be the "awaitable" that the coroutine co_awaited on. That is, there's some process that will produce a value, you co_await on the future that this process returns, and it is that process which will resume your coroutine once the value is ready. If someone else needs to co_await on the value your coroutine produces, that's fine. Your promise/future machinery will resume them at the completion of your coroutine and give them your promise's value.

That's how co_await coroutines are meant to be resumed. Code outside of this process doesn't need a handle and shouldn't get one.

In any case, unless the promise/future machinery of a coroutine explicitly gives you an API to extract a handle, you can't get a handle.

Upvotes: 2

Related Questions