【问题标题】:Implementing example from coroutines TS 2017从协程 TS 2017 实现示例
【发布时间】:2018-09-13 09:15:21
【问题描述】:

C++ coroutines TS (2017) 中有一个可等待对象的示例。

 template <class Rep, class Period>
 auto operator co_await(std::chrono::duration<Rep, Period> d) {
    struct awaiter {
        std::chrono::system_clock::duration duration;
        ...
        awaiter(std::chrono::system_clock::duration d) : duration(d){}
        bool await_ready() const { return duration.count() <= 0; }
        void await_resume() {}
        void await_suspend(std::experimental::coroutine_handle<> h){...}
    };

    return awaiter{d};
  }

  using namespace std::chrono;
  my_future<int> h();
  my_future<void> g() {
      std::cout << "just about go to sleep...\n";
      co_await 10ms;
      std::cout << "resumed\n";
      co_await h();
  }

像典型的 StackOverflow 问题一样,它不会编译。悄悄骂了一阵子,我决定把它变成一个【MCVE】——用来学习。下面的代码在启用 /await 的 VC++17 上编译和运行。我认为它可能大致符合 TS 作者的意图。唉,它使用了一个分离的线程。通过joinfuture::getsignal_all_at_thread_exit() 或...

例如,不能将连接添加到awaiter 的析构函数。在生成的线程中,h.resume() 导致等待者对象被移动到生成的线程中,并在那里调用其(默认)构造函数。所以析构函数在与构造函数不同的线程中被调用。

问题,除了“这是 TS 的意图吗?”之外,是 “是否可以以合理经济的方式进行改进,以处理悬空线程?”(如果是的话怎么办?)

#include <experimental/coroutine>
#include <future>
#include <thread>

namespace xtd = std::experimental;

template <class Rep, class Period>
auto operator co_await(std::chrono::duration<Rep, Period> dur) {

    struct awaiter {
        using clock = std::chrono::high_resolution_clock;
        clock::time_point resume_time;

        awaiter(clock::duration dur) : resume_time(clock::now()+dur) {}

        bool await_ready() { return resume_time <= clock::now(); }

        void await_suspend(xtd::coroutine_handle<> h) {
            std::thread([=]() {
                std::this_thread::sleep_until(resume_time); 
                h.resume(); // destructs the obj, which has been std::move()'d
            }).detach(); // Detach scares me.
        }
        void await_resume() {}
    };

    return awaiter{ dur };
}

using namespace std::chrono;

std::future<int> g() {
    co_await 4000ms;
    co_return 86;
}


template<typename R>
  bool is_ready(std::future<R> const& f)
  { return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready; }

int main() {
    using std::cout;
    auto gg = g();
    cout << "Doing stuff in main, while coroutine is suspended...\n";
    std::this_thread::sleep_for(1000ms);
    if (!is_ready(gg)) {
        cout << "La lala, lala, lala...\n";
        std::this_thread::sleep_for(1500ms);
    }

    cout << "Whew! Done. Getting co_return now...\n";
    auto ret = gg.get();
    cout << "coroutine resumed and co_returned " << ret << '\n';
    system("pause");
    return ret;
}

【问题讨论】:

    标签: c++ multithreading coroutine


    【解决方案1】:

    能否以合理经济的方式对此进行改进,以处理悬空线程?

    您可以使用“线程池”实现,而不是按需分离线程。

    这是玩具示例: https://gist.github.com/yohhoy/a5ec6d4aeeb4c60d3e4f3adfd1df9ebf

    【讨论】:

      猜你喜欢
      • 2018-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-10
      • 1970-01-01
      相关资源
      最近更新 更多