日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++?Boost?Coroutine使用協程詳解_C 語言

作者:無水先生 ? 更新時間: 2022-12-19 編程語言

一、說明語言擴展

以下庫擴展了編程語言 C++。

  • Boost.Coroutine 使得在 C++ 中使用協程成為可能——其他編程語言通常通過關鍵字 yield 支持。
  • Boost.Foreach 提供了一個基于范圍的 for 循環,它是在 C++11 中添加到語言中的。
  • Boost.Parameter 允許您以名稱/值對的形式并以任何順序傳遞參數——例如,這在 Python 中是允許的。
  • Boost.Conversion 提供了兩個轉換運算符來替換 dynamic_cast 并允許您區分向下轉換和交叉轉換。

二、庫Boost.Coroutine

通過 Boost.Coroutine,可以在 C++ 中使用協程。協程是其他編程語言的一個特性,通常使用關鍵字 yield 來表示協程。在這些編程語言中,yield 可以像 return 一樣使用。但是,當使用 yield 時,該函數會記住該位置,如果再次調用該函數,將從該位置繼續執行。

C++ 沒有定義關鍵字 yield。但是,使用 Boost.Coroutine 可以從函數返回并稍后從同一位置繼續。 Boost.Asio 庫也使用 Boost.Coroutine 并受益于協程。

三、示例和代碼

Boost.Coroutine 有兩個版本。本章介紹第二個版本,即當前版本。這個版本從 Boost 1.55.0 開始可用,并取代了第一個版本。

示例 51.1。使用協程

#include <boost/coroutine/all.hpp>
#include <iostream>
using namespace boost::coroutines;
void cooperative(coroutine<void>::push_type &sink)
{
  std::cout << "Hello";
  sink();
  std::cout << "world";
}
int main()
{
  coroutine<void>::pull_type source{cooperative};
  std::cout << ", ";
  source();
  std::cout << "!\n";
}

Example51.1

示例 51.1 定義了一個函數 cooperative(),它作為協程從 main() 調用。 cooperative() 提前返回 main() 并被第二次調用。在第二次調用時,它會從中斷處繼續。

要將 cooperative() 用作協程,使用類型 pull_type 和 push_type。這些類型由 boost::coroutines::coroutine 提供,這是一個在示例 51.1 中用 void 實例化的模板。

要使用協程,您需要 pull_type 和 push_type。其中一種類型將用于創建一個對象,該對象將使用您想用作協程的函數進行初始化。另一種類型將是協程函數的第一個參數。

示例 51.1 在 main() 中創建了一個名為 source 的 pull_type 類型的對象。 cooperative() 傳遞給構造函數。 push_type 用作 cooperative() 簽名中的唯一參數。

創建源時,傳遞給構造函數的函數 cooperative() 會立即作為協程調用。發生這種情況是因為源基于 pull_type。如果源基于 push_type,則構造函數不會將 cooperative() 作為協程調用。

cooperative() 將 Hello 寫入標準輸出。之后,函數像訪問函數一樣訪問 sink 。這是可能的,因為 push_type 重載了 operator()。 main() 中的 source 表示協程 cooperative(),cooperative() 中的 sink 表示函數 main()。調用 sink 使 cooperative() 返回,而 main() 從調用 cooperative() 的地方繼續,并將逗號寫入標準輸出。

然后,main() 調用 source 就好像它是一個函數一樣。同樣,這是可能的,因為重載了 operator()。這一次,cooperative() 從中斷點繼續并將世界寫入標準輸出。因為 cooperative() 中沒有其他代碼,協程結束。它返回到 main(),它將一個感嘆號寫入標準輸出。

結果是示例 51.1 顯示 Hello, world!

您可以將協程視為協作線程。在某種程度上,函數 main() 和 cooperative() 同時運行。代碼在 main() 和 cooperative() 中輪流執行。每個函數內的指令按順序執行。多虧了協程,一個函數不需要在另一個函數執行之前返回。

示例 51.2。從協程返回一個值

#include <boost/coroutine/all.hpp>
#include <functional>
#include <iostream>
using boost::coroutines::coroutine;
void cooperative(coroutine<int>::push_type &sink, int i)
{
  int j = i;
  sink(++j);
  sink(++j);
  std::cout << "end\n";
}
int main()
{
  using std::placeholders::_1;
  coroutine<int>::pull_type source{std::bind(cooperative, _1, 0)};
  std::cout << source.get() << '\n';
  source();
  std::cout << source.get() << '\n';
  source();
}

Example51.2

示例 51.2 與前面的示例類似。這次模板 boost::coroutines::coroutine 是用 int 實例化的。這使得從協程返回一個 int 給調用者成為可能。

傳遞 int 值的方向取決于使用 pull_type 和 push_type 的位置。該示例使用 pull_type 在 main() 中實例化一個對象。 cooperative() 可以訪問 push_type 類型的對象。 push_type 發送一個值,pull_type 接收一個值;因此,設置了數據傳輸的方向。

cooperative() 調用 sink,參數類型為 int。此參數是必需的,因為協程是使用數據類型 int 實例化的。通過使用由 pull_type 提供的成員函數 get() 從 main() 中的 source 接收傳遞給 sink 的值。

示例 51.2 還說明了如何將具有多個參數的函數用作協程。 cooperative() 有一個額外的 int 類型參數,不能直接傳遞給 pull_type 的構造函數。該示例使用 std::bind() 將函數與 pull_type 鏈接起來。

該示例將 1 和 2 后跟 end 寫入標準輸出。

示例 51.3。將兩個值傳遞給協程

#include <boost/coroutine/all.hpp>
#include <tuple>
#include <string>
#include <iostream>
using boost::coroutines::coroutine;
void cooperative(coroutine<std::tuple<int, std::string>>::pull_type &source)
{
  auto args = source.get();
  std::cout << std::get<0>(args) << " " << std::get<1>(args) << '\n';
  source();
  args = source.get();
  std::cout << std::get<0>(args) << " " << std::get<1>(args) << '\n';
}
int main()
{
  coroutine<std::tuple<int, std::string>>::push_type sink{cooperative};
  sink(std::make_tuple(0, "aaa"));
  sink(std::make_tuple(1, "bbb"));
  std::cout << "end\n";
}

Example51.3

示例 51.3 在 main() 中使用 push_type,在 cooperative() 中使用 pull_type,這意味著數據從調用方傳輸到協程。

此示例說明如何傳遞多個值。 Boost.Coroutine 不支持傳遞多個值,因此必須使用元組。您需要將多個值打包到元組或其他結構中。

示例 51.3 顯示 0 aaa、1 bbb 和 end。

示例 51.4。協程和異常

#include <boost/coroutine/all.hpp>
#include <stdexcept>
#include <iostream>
using boost::coroutines::coroutine;
void cooperative(coroutine<void>::push_type &sink)
{
  sink();
  throw std::runtime_error("error");
}
int main()
{
  coroutine<void>::pull_type source{cooperative};
  try
  {
    source();
  }
  catch (const std::runtime_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

協程在拋出異常時立即返回。異常被傳輸到協程的調用者,在那里它可以被捕獲。因此,異常與常規函數調用沒有什么不同。

示例 51.4 顯示了這是如何工作的。此示例會將字符串錯誤寫入標準輸出。

原文鏈接:https://yamagota.blog.csdn.net/article/details/127963272

欄目分類
最近更新