背景:
最新版的asio(1-13-0)的api添加了对co_await的支持 (之前的版本也支持一些,只不过命名空间还没有正式放入asio)。
我打算学习下asio,也打算抛弃自己的网络库了,也期望其他的库或者driver能够统一的使用asio+co_await,这样我们应用程序开发者就能快速的引入库(少一些心智负担,不用担心线程/同步/异步/生命周期管理等各种模型差异性导致的顾虑)。[当然我也并不是说asio就是最好的选择,但是大家都基于某个统一的库去做开发,还是有很多好处的]。
目的:
我的目的是采用 asio+await开发一个同步非阻塞RPC(嗯,就是类似golang grpc),来替换调我的异步RPC,进而通过它再重新开发Orleans-CPP简易版本。
通过我个人理解,要实现同步RPC(当然也包括其他基于协程的应用)我们需要先实现几个基础功能):
- Channel - 用于实现协程之间的pipeline
- Mutex - 基于协程的锁
- WaitGroup - 基于协程的等待对象
- CondVariables
- ……(带补充)
因为同步RPC库(支持多个协程使用同一个RPC对象去调用服务)的实现(个人理解,我本打看看grpc怎么做的,但时间还不够,所以~~~)大概如下:
开启一个writer协程,使用channel收集其他协程(调用RPC函数时)产生的消息(消息里包括一个request msg、一个用于接收此次请求的response的channel),开启一个receive协程,来接收服务器的网络消息,并且从中解析各个respnse,并且根据其seqid (通过锁)拿到其对应的调用者的channel,然后将response放入channel,以此唤醒调用者。
简要实现:
下面是我写的简易版channel和协程锁的实现(我这几天才开始学习asio,所以难免有一些问题或者错误处理省略了,还请指教)
//
// echo_server.cpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <cstdio>
#include <queue>
#include <mutex>
#include <iostream>
#include <asio/co_spawn.hpp>
#include <asio/detached.hpp>
#include <asio/io_context.hpp>
#include <asio/ip/tcp.hpp>
#include <asio/signal_set.hpp>
#include <asio/write.hpp>
#include <asio/awaitable.hpp>
#include <asio/redirect_error.hpp>
using asio::ip::tcp;
using asio::awaitable;
using asio::co_spawn;
using asio::detached;
using asio::use_awaitable;
using asio::redirect_error;
namespace this_coro = asio::this_coro;
template<typename T>
class Channel : public asio::noncopyable
{
public:
using Ptr = std::shared_ptr<Channel<T>>;
using Container = std::queue<T>;
static Ptr Make(asio