C ++ 20 coroutines by example

In anticipation of the start of the "C ++ Developer. Professional" course , we invite you to sign up for an open webinar on the topic "Backend in modern C ++".



We also share the traditional translation of useful material.










C++20 . — , ​​ . , - :





  • co_await



    ,





  • co_return



    , ()





  • co_yield



    ,





. C++20 , , . , , . , cppcoro.





cppcoro



C++20, (task



), (generator



) async_generator



. , ( , (awaited)), — T, ( begin()



, , ++



).





. produce_items()



, co_yield



cppcoro::generator<std::string>



, -.





#include <cppcoro/generator.hpp>

cppcoro::generator<std::string> produce_items()
{
  while (true)
  {
     auto v = rand();
     using namespace std::string_literals;
     auto i = "item "s + std::to_string(v);
     print_time();
     std::cout << "produced " << i << '\n';
     co_yield i;
  }
}
      
      



: rand()



. .





, , co_yield



. , . :





#include <cppcoro/task.hpp>

cppcoro::task<> consume_items(int const n)
{
  int i = 1;
  for(auto const& s : produce_items())
  {
     print_time();
     std::cout << "consumed " << s << '\n';
     if (++i > n) break;
  }

  co_return;
}
      
      



consume_items



. co_return



, — cppcodo::task<>



, . n , for



. begin()



cppcoro::generator<std::string>



, , ++



. produce_items()



() . , , begin()



++



. produce_items()



, .





consume_items()



main()



. , main()



, co_await



. , cppcoro syncwait()



, awaitable



( ). coawait. .





, require_items()



main()



:





#include <cppcoro/sync_wait.hpp>
 
int main()
{
   cppcoro::sync_wait(consume_items(5));
}
      
      



:





cppcoro::generator<T>



, . , co_await



, , . cppcoro cppcoro::async_generator<T>



, .





: , , next_value()



. , . produce_items()



, . — cppcoro::async_generator<T>



.





#include <cppcoro/async_generator.hpp>

cppcoro::task<int> next_value()
{
  using namespace std::chrono_literals;
  co_await std::chrono::seconds(1 + rand() % 5);
  co_return rand();
}

cppcoro::async_generator<std::string> produce_items()
{
  while (true)
  {
     auto v = co_await next_value();
     using namespace std::string_literals;
     auto i = "item "s + std::to_string(v);
     print_time();
     std::cout << "produced " << i << '\n';
     co_yield i;
  }
}
      
      



, . co_await



for



:





cppcoro::task<> consume_items(int const n)
{
  int i = 1;
  for co_await(auto const& s : produce_items())
  {
     print_time();
     std::cout << "consumed " << s << '\n';
     if (++i > n) break;
  }
}
      
      



co_return



, . co_await



for



, . co_return



, cppcoro::task<>



, , return



, void



. , co_await



, , co_return



, .





main()



. , , , :





, print_time()



, , :





void print_time()
{
   auto now = std::chrono::system_clock::now();
   std::time_t time = std::chrono::system_clock::to_time_t(now);   

   char mbstr[100];
   if (std::strftime(mbstr, sizeof(mbstr), "[%H:%M:%S] ", std::localtime(&time))) 
   {
      std::cout << mbstr;
   }
}
      
      



, , — , co_await



. co_await



. Windows :





#include <windows.h>

auto operator co_await(std::chrono::system_clock::duration duration)
{
   class awaiter
   {
      static
         void CALLBACK TimerCallback(PTP_CALLBACK_INSTANCE,
            void* Context,
            PTP_TIMER)
      {
         stdco::coroutine_handle<>::from_address(Context).resume();
      }
      PTP_TIMER timer = nullptr;
      std::chrono::system_clock::duration duration;
   public:

      explicit awaiter(std::chrono::system_clock::duration d) 
         : duration(d)
      {}

      ~awaiter()
      {
         if (timer) CloseThreadpoolTimer(timer);
      }

      bool await_ready() const
      {
         return duration.count() <= 0;
      }

      bool await_suspend(stdco::coroutine_handle<> resume_cb)
      {
         int64_t relative_count = -duration.count();
         timer = CreateThreadpoolTimer(TimerCallback,
            resume_cb.address(),
            nullptr);
         bool success = timer != nullptr;
         SetThreadpoolTimer(timer, (PFILETIME)&relative_count, 0, 0);
         return success;
      }

      void await_resume() {}

   };
   return awaiter{ duration };
}
      
      



Coroutines in Visual Studio 2015 - Update 1.





: . .





, :





  • C++20 Coroutines





  • Exploring MSVC Coroutine





  • Coroutine Theory





  • C++ Coroutines: Understanding operator co_await





  • C++ Coroutines: Understanding the promise type






"C++ Developer. Professional".









"Backend C++".












All Articles