美文网首页
C++11 使用boost::coroutine2 有栈协程实现

C++11 使用boost::coroutine2 有栈协程实现

作者: FredricZhu | 来源:发表于2023-08-27 15:05 被阅读0次

因为本机没有安装 g++ 9.x,所以不具备开启C++20的功能。而《Design Patterns in Modern C++》一书中却有一个使用协程编写二叉树迭代器的示例。如果你是C++20的编译器,建议直接使用标准库的std::generator类,比这个清晰,高效,大致写法如下,


image.png

怎么样,是不是又骚又靓丽。

如果你跟我一样,只能使用12年以前的C++11编译器,例如g++ 7.x,那么下面这篇文章是一个可行的替代方案。

还有一个方案是使用boost的outcome库,但是对boost版本要求比较高,得一个一个试,放弃了。你要知道我平时用的多的两个库是OpenCV和boost,boost动了,OpenCV可能不兼容,所以尽量不要干这种事儿,太恶心了。[其中boost::outcome库的实现方案和std差不多,直接换下名称空间就行了,非常直观,这里就不废话了]

本次方案使用boost::coroutines2::coroutine的push_type和pull_type实现。兼容C++11以上版本。

conanfile.txt

[requires]
boost/1.72.0
opencv/4.5.3



[generators]
cmake

CMakeLists.txt

cmake_minimum_required(VERSION 3.3)

project(90_binary_tree_iterator_coroutine)

set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig/")

set ( CMAKE_CXX_FLAGS "-pthread")
set(CMAKE_CXX_STANDARD 17)
add_definitions(-g)
set(${CMAKE_BINARY_DIR} ${CMake_CURRENT_SOURCE_DIR}/build)


include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()



include_directories(${INCLUDE_DIRS})
LINK_DIRECTORIES(${LINK_DIRS})

file( GLOB main_file_list ${CMAKE_CURRENT_SOURCE_DIR}/*_test.cpp) 
file( GLOB sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)

foreach( main_file ${main_file_list} )
    file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${main_file})
    string(REPLACE ".cpp" "" file ${filename})
    add_executable(${file}  ${main_file} ${sources})
    target_link_libraries(${file} PRIVATE  pthread)
    target_link_libraries(${file} PRIVATE  ${CONAN_LIBS})


endforeach( main_file ${main_file_list})

binary_tree_iterator_coroutine.hpp

#ifndef _FREDIRC_BINARY_TREE_ITERATOR_COROUTINE_HPP_
#define _FREDIRC_BINARY_TREE_ITERATOR_COROUTINE_HPP_

#include <boost/coroutine2/all.hpp>
#include <string>

template <typename T>
using coroutine = boost::coroutines2::coroutine<T>;

template <typename T>
struct BinaryTree;

template <typename T>
struct Node {
    T value {};

    Node<T>* left{nullptr}, *right{nullptr}, *parent{nullptr};

    BinaryTree<T>* tree{nullptr};

    Node(T value_): value(value_) {}

    Node(T value_, Node<T>* left_, Node<T>* right_):
        value(value_), left(left_), right(right_) {
        // 初始化左子节点和右子节点的树为同一棵树
        this->left->tree = this->right->tree = tree;
        // 初始化左子节点和右子节点的父节点为当前节点
        this->left->parent = this->right->parent = this; 
    }

    void setTree(BinaryTree<T>* t) {
        tree = t;
        if(left) left->tree = t;
        if(right) right->tree = t;
    }
    
    ~Node() {
        if(left) delete left;
        if(right) delete right;
    }
};


template <typename T>
struct BinaryTree {
    
    Node<T>* root {nullptr};

    BinaryTree(Node<T>* root_):
        root(root_) {
            root->setTree(this);
        }
    
    ~BinaryTree() {
        if(root) {
            delete root;
        }
    }

   
};

template <class T>
void post_order(typename coroutine<Node<T>*>::push_type& sink, Node<T>* node) { 
    if(node->left) {    
        post_order<T>(sink, node->left); 
    }   
    if(node->right) { 
        post_order<T>(sink, node->right); 
    } 
    sink(node); 
} 

using cort_string_node = coroutine<Node<std::string>*>;

#endif

oop_test.cpp

#include <iostream>
#include <string>
#include <sstream>
#include "log.h"
#include <utility>
#include <memory>
#include <cstring>
#include <vector>
#include <iterator>
#include "binary_tree_iterator_coroutine.hpp"

#define BOOST_TEST_MODULE BinaryTreeIteratorCoRoutine
#include "test.hpp"


BOOST_AUTO_TEST_SUITE(Suite01, *fixture<SuiteSetUp>())

BOOST_AUTO_TEST_CASE(BinaryTreeIteratorCoRoutineTest) {
    BinaryTree<std::string> family (
        new Node<std::string>("me",        
        new Node<std::string>("Mother",
            new Node<std::string>("Mother's mother"),
            new Node<std::string>("Mother's father")),
        new Node<std::string>("father"))
    );

    cort_string_node::pull_type source([&](cort_string_node::push_type& sink){
        post_order<std::string>(sink, family.root);
    });

    for(auto const& node: source) {
        std::cout << node->value << std::endl;
    }
}

BOOST_AUTO_TEST_SUITE_END()

上面代码要注意的一个地方是post_order第一个参数的前面要加个typename,这8个字母一个字母一块钱,坑得很。原因是模板参数里面带有多个命名空间限定的话,还外带这种 <T>参数的话,编译器默认不认定为模板,会触发编译错误。

程序输出如下,


image.png

相关文章

  • boost::coroutine2 的简单使用

    介绍 本文主要介绍了怎么通过 boost::coroutine2 来在 C++ 代码中使用协程,详细的介绍请移步 ...

  • Ceph RGW multisite代码实现

    multisite代码中大量使用了Boost的协程,在了解协程的使用方法后,整体代码结构还是比较清晰的。 协程实现...

  • [libco] 协程栈空间

    协程“栈”空间,有独立栈和共享栈,重点理解一下协程共享栈。 文章来源:[libco] 协程栈空间[https://...

  • 协程

    对于协程做一个整体的描述,从概念、原理、实现三个方面叙述。侧重有栈协程。 1 概览 1.1 什么是协程 有很多与协...

  • Goroutine 随笔

    很早之前在lua中实现过一版协程,lua的栈是虚拟的,当要切换协程时虚拟栈不需要退栈,只需要从C的栈(物理栈)退出...

  • Libco协程库实现

    腾讯开源的Libco协程库,以前看过部分源码,所有的协程都用数组模拟栈表示,里面使用到的技术点有hook系统函数,...

  • 协程池糗百爬虫(五)

    使用协程池实现爬虫的具体实现

  • 四、生命周期:2、协程详解

    1、协程常规使用方式 2、协程嵌套协程测试 3、协程实现返回值机制 协程可以传递参数进入,但是没有返回值功能,有时...

  • 记boost协程切换bug发现和分析

    在分析了各大开源协程库实现后,最终选择参考boost.context的汇编实现,来写tbox的切换内核。 在这过程...

  • Kotlin Primer·第七章·协程库(上篇)

    本篇只讲了协程库的使用。还有中篇讲协程的启动和切换实现原理,下篇核心讲解kotlin协程在JVM层的实现原理。这可...

网友评论

      本文标题:C++11 使用boost::coroutine2 有栈协程实现

      本文链接:https://www.haomeiwen.com/subject/ocdwmdtx.html