从coroutines TS 2017实施示例

时间:2018-04-03 23:06:46

标签: c++ multithreading coroutine

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] - 用于学习。下面的代码编译并在VC ++ 17上运行并启用/ await。我认为这可能与TS作者的意图大致相同。唉,它采用了一个独立的线程。很难看出如何通过joinfuture::getsignal_all_at_thread_exit()或......来收集该帖子。

例如,无法将join添加到awaiter的析构函数中。在生成的线程中,h.resume()导致awaiter对象被移动到生成的线程及其(默认)构造函数中。因此析构函数在与构造函数不同的线程中调用。

问题,除了“这是TS的意图吗?”之外,“能以合理经济的方式改进这种悬挂线程吗?” / strong>(如果是这样的话?)

#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;
}

1 个答案:

答案 0 :(得分:0)

  

能以合理的经济方式改善这种倾向吗?

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

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