C++跨平台协程实现

概念

1、进程

  • 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。
  • 进程和进程之间占有独立的内存空间,不共享数据,不同进程之间可以通过FIFO,PIPE等共享数据。

2、线程

  • 线程是进程的一个执行单元,是CPU调度和分配的基本单位。
  • 线程不具有独立的运行资源,进程内的不同线程共享进程分配到的内存空间。
  • 线程和线程之间通过内存共享共享数据,可以较为快速的进行context切换。资源开销较小。

3、协程

  • 协程是用户态轻量级线程。虽然叫用户态线程,但是协程的create并不需要调用系统资源,而是由语言内部进行实现的。所以协程可以大量创建。
  • 协程是跑在线程上的线程片,并且可以人为的选择创建,销毁,切换,挂起,恢复。
  • 协程和线程之间最大的不同在于,对于多核CPU,线程可以并行执行程序,而协程是跑在线程上的线程片,只能并发。
  • 协程在并发上的修饰在于,创建,切换所消耗的资源远远小于线程创建和切换的开销。所以,对于IO密集型场景,协程就极为匹配。

三者之间的关系,可以用图片表示
在这里插入图片描述

还有就是有很多小伙伴会问,协程既然这么好用,其使用场景是什么。网上有很多讲协程的文章,但是的确没有怎么说,协程的使用场景。现在很多互联网大厂都在致力于做自己的编译器和脚本运行工具,当脚本语言在运行到异步逻辑的时候,如果都通过线程和加锁来实现,无疑,这样,脚本的运行效率会相当低下。这时,如果用协程来实现脚本运行阶段的异步逻辑,会大大加速脚本的运行速度。

C++实现

c++ 实现协程分系统不同,有不同实现。

1、windows系统

windows系统中,微软针对coroutine提供了自己的一套API,起了一个名字叫Fiber(纤程),这组API智能在windows平台进行使用,无法跨平台。Fiber的两个特点

  • 纤程拥有独立的栈空间和寄存器环境;
  • 纤程在用户态实现调调度,也就是说完全由程序员控制;

接下来,来了解一下windows系统下如何使用这套API

  • 线程转换为纤程
LPVOID ConvertThreadToFiberEx(
  [in, optional] LPVOID lpParameter,//指针类型数据传入,可以通过GetFiberData索回数据
  [in]           DWORD  dwFlags /*可以填0和 FIBER_FLAG_FLOAT_SWITCH 两种状态。
  0的话,因为x86系统的CPU的浮点数状态信息默认情况下在纤程看来不属于CPU寄存器,浮点运算会导致错误。
  FIBER_FLAG_FLOAT_SWITCH可以解决这个问题*/
);

此接口是为了让开发者能够使用Fiber调度所进行操作。要想使用Fiber,就要把当前线程变成Fiber。需要注意的是此接口只在windowsXP之上的系统可以使用,而windowsXP系统,使用如下接口。

LPVOID ConvertThreadToFiber(
  [in, optional] LPVOID lpParameter
);

ConvertThreadToFiber(Ex)返回Fiber的运行地址,之后就可以使用这个地址。

  • 创建纤程

我们将线程转换成Fiber是为了有多个Fiber能够并发,这就需要我们进行Fiber的创建。

LPVOID CreateFiberEx(
  [in]           SIZE_T                dwStackCommitSize, //堆栈的初始化大小,默认为1MB(默认填0)
  [in]           SIZE_T                dwStackReserveSize,//预留的虚拟内存,默认为1MB(默认填0)
  [in]           DWORD                 dwFlags,
  [in]           LPFIBER_START_ROUTINE lpStartAddress, // Fiber运行函数指针
  [in, optional] LPVOID                lpParameter
);

同样,windowsXP版本之上才能够使用,XP版本使用

LPVOID CreateFiber(
  [in]           SIZE_T                dwStackSize,
  [in]           LPFIBER_START_ROUTINE lpStartAddress,
  [in, optional] LPVOID                lpParameter
);

像ConvertThreadToFiber(Ex)函数一样,CreateFiber(Ex)也返回纤程执行环境的内存地址,这个内存地址就像句柄一样,直接标识着一个纤程。

  • 切换纤程

创建纤程后,系统不会像开辟Thread时,自动运行,而是需要程序中由程序员决定何时运行。这就需要用到纤程的切换

void SwitchToFiber(
  [in] LPVOID lpFiber
);

lpFiber就是ConvertThreadToFiber(Ex)和CreateFiber(Ex)的返回值。

  • 删除纤程

当一个纤程运行完毕之后,需要删除,调用删除纤程的接口

void DeleteFiber(
  [in] LPVOID lpFiber
);

2、Linux系统

前文提到,Fiber只能在windows系统中使用,在linux上,需要用到ucontext。

the ucontext_t type is a structure type suitable for holding the context for the user thread of execution. A thread’s context include stack,saved registersm a list of block signals

这需要引入头文件
<ucontext.h>
其中包含了ucontext_t和配套的四个函数

#include <ucontext.h>
typedef struct ucontext_t {
  struct ucontext_t* uc_link;
  stack_t uc_stack;
  __sigset_t uc_sigmask;
  mcontext_t uc_mcontext;
  ...
};
  • uc_link 后续执行的context,若uc_link为空,当前context执行完毕后,退出程序
  • uc_stack 当前context的栈
  • uc_sigmask 当前context需要屏蔽的信号集合
  • uc_mcontext 保存上下文的特定机器, 包括调用线程的特定寄存器等等
#include <ucontext.h>
int getcontext(ucontext_t* ucp);
void makecontext(ucontext_t* ucp, void (*func)(), int argc, ...);
int swapcontext(ucontext_t* olducp, ucontext_t* newucp);
int setcontext(const ucontext_t* ucp);
  • getcontext

创建一个ucontext_t对象,进行执行空间分配
创建方式:
(1) getcontext,
(2) 指定分配给上下文的栈uc_stack.ss_sp,
(3) 指定这块栈的大小uc_stack.ss_size,
(4) 指定uc_stack.ss_flags,
(5) 指定后继上下文uc_link

ucontext_t ucp;
getcontext(&ucp);
ucp.uc_stack.ss_sp = new char[100];
ucp.uc_stack.ss_size = new char[100];
ucp.uc_stack.ss_flags = 0;

协程运行时使用主协程划分的栈空间,而协程切回主线程时需要将该部分栈空间的内容copy到每个协程各自的一个空间缓存起来,因为主协程中划分的栈空间并不是只用于一个协程,而是会用于多个协程

  • makecontext

makecontext可以修改getcontext初始化过的context,func参数指明了该context的入口函数,argc是入参个数

  • swapcontext

切换context,保存当前context并切换到新的context运行

  • setcontext

将当前程序切换到新的context,在执行正确的情况下该函数直接切换到新的执行状态,不会返回。

代码实现

思路

  • 协程调度类,可以当做协程池,用来管理用户协程对象
  • 用户协程类,用户协程类负责实际的协程接口实现,以及任务相关的部分
  • 任务类,用来执行具体业务

代码结构

在这里插入图片描述

  • corountine.h 和 coroutine.cpp 是用户携程类
  • coroutine_pool.h 和 coroutine_pool.h 是协程调度类,也就是协程池
  • coroutine_task.h 和 count.h 分别是任务类基类以及具体实现数数的任务类
  • coroutine_common.h 和 type.h 是自定义资源

代码具体实现在附录

附录

  • coroutine.h
#pragma once
#ifndef __Coroutine_H__
#define __Coroutine_H__
#include "type.h"
#include "coroutine_common.h"
#include "coroutine_task.h"
class CoroutinePool;
class Coroutine
{
public:
	Coroutine(CoroutineId id, std::shared_ptr<CoroutinePool> coroutinePool);
	virtual ~Coroutine();

public:
	error_t initialize();

	void unInitialize();

	error_t setStatus(const CoroutineStatusEnum& status);

	CoroutineStatusEnum getStatus() const;

	void setResumeReason(const ResumeReason& reason);

	ResumeReason getResumeReason() const;

	CoroutineId getCoroutineId() const;

	error_t setCoroutineTask(const CoroutineTaskPtr& task);

	CoroutineContext getContext() const;

	static void coroutineEntry(void* lpParameter);

	void resetContext();

private:

	error_t getCoroutinePool(OUT std::shared_ptr<CoroutinePool>& coroutinePool);

	CoroutineContext getMainContext() const;

	void run();

private:
	std::weak_ptr<CoroutinePool>      m_coroutinePool;
	CoroutineId                       m_coroutineId;
	CoroutineTaskPtr                  m_coroutineTask;
	CoroutineStatusEnum				  m_coroutineStatus;
	CoroutineContext                  m_context;
	ResumeReason                      m_resumeReason;
};

using CoroutinePtr = std::shared_ptr<Coroutine>;

#endif __Coroutine_H__
  • couroutine.cpp
#include "corountine.h"
#include "coroutine_task.h"
#include "coroutine_pool.h"

Coroutine::Coroutine(CoroutineId id, std::shared_ptr<CoroutinePool> coroutinePool) :
	m_coroutinePool(coroutinePool),
	m_coroutineId(id),
	m_coroutineTask(nullptr),
	m_coroutineStatus(CoroutineStatusEnum::COROUTINE_STATUS_UNKNOWN),
	m_context(nullptr),
	m_resumeReason(ResumeReason::REASON_NORMAL)
{
}

Coroutine::~Coroutine()
{
	unInitialize();
}

error_t Coroutine::initialize()
{
#ifdef PLATFORM_WIN32
	m_context = nullptr;
#elif defined(PLATFORM_LINUX)
	getcontext(m_context);
	m_context->uc_stack.ss_sp = new char[INIT_STACK];
	if (nullptr == m_context->uc_stack.ss_sp)
	{
		return -1;
	}
	m_context->uc_stack.ss_size = INIT_STACK;
#endif PLATFORM_WIN32
	return 0;
}

void Coroutine::unInitialize()
{
#ifdef PLATFORM_WIN32
	if (nullptr != m_context)
	{
		DeleteFiber(m_context);
		m_context = nullptr;
	}
#elif defined(PLATFORM_LINUX)
	if (nullptr != m_context
		&& nullptr != m_context->uc_stack.ss_sp)
	{
		delete[]  m_context->uc_stack.ss_sp;
		m_context->uc_stack.ss_sp = nullptr;
	}
	if (nullptr != m_context)
	{
		delete m_context;
		m_context = nullptr;
	}
#endif
	m_coroutineTask = nullptr;
}

error_t Coroutine::setStatus(const CoroutineStatusEnum& status)
{
	m_coroutineStatus = status;
	return 0;
}

CoroutineStatusEnum Coroutine::getStatus() const
{
	return m_coroutineStatus;
}

void Coroutine::setResumeReason(const ResumeReason& reason)
{
	m_resumeReason = reason;
}

ResumeReason Coroutine::getResumeReason() const
{
	return m_resumeReason;
}

CoroutineId  Coroutine::getCoroutineId() const
{
	return m_coroutineId;
}

error_t Coroutine::setCoroutineTask(const CoroutineTaskPtr& task)
{
	error_t errorCode = 0;
	if (nullptr == task)
	{
		return -1;
	}
	// 设置协程任务
	m_coroutineTask = task;
#ifdef PLATFORM_WIN32
	if (nullptr != m_context) 
	{
		DeleteFiber(m_context);
		m_context = nullptr;
	}
	// 创建协程
	LPVOID fiber = CreateFiberEx(INIT_STACK, INIT_STACK, FIBER_FLAG_FLOAT_SWITCH, (LPFIBER_START_ROUTINE)Coroutine::coroutineEntry, (LPVOID)(this));
	if (nullptr == fiber)
	{
		return -1;
	}
	else
	{
		m_context = fiber;
		m_coroutineStatus = CoroutineStatusEnum::COROUTINE_STATUS_READY;
		// 切换协程
		SwitchToFiber(m_context);
	}
#else
	// 获取主协程
	CoroutinePoolPtr pCoroutinePool = m_coroutinePool.lock();
	//设置当前协程执行完成后,切回到主协程
	m_context->uc_link = pCoroutinePool->getMainCoroutineContext();
	//设置协程入口
	makecontext(m_context, (void(*)(void))coroutineEntry, 1, this);
	//设置当前运行协程为m_context
	if (0 != swapcontext(pCoroutinePool->getMainCoroutineContext(), m_context))
	{
		return -1;
	}
#endif
	return 0;
}

CoroutineContext Coroutine::getContext() const
{
	return m_context;
}

void Coroutine::coroutineEntry(void* lpParameter)
{
	Coroutine* coroutine = reinterpret_cast<Coroutine*>(lpParameter);
	if (nullptr != coroutine)
	{
#ifdef PLATFORM_WIN32
#else
		ucontext_t cur;
		getcontext(&cur);
#endif
		coroutine->run();
		{
			CoroutinePoolPtr pCoroutinePool = coroutine->m_coroutinePool.lock();
			error_t errorCode = 0;
			errorCode = pCoroutinePool->moveRunningToIdleCoroutine();
			if (0 != errorCode)
			{
				return;
			}
		}
#ifdef PLATFORM_WIN32
		SwitchToFiber(coroutine->getMainContext());
#else
		ucontext_t cur2;
		getcontext(&cur2);
#endif
	}
}

error_t Coroutine::getCoroutinePool(OUT std::shared_ptr<CoroutinePool>& coroutinePool)
{
	coroutinePool = m_coroutinePool.lock();
	return 0;
}

CoroutineContext Coroutine::getMainContext() const
{
	CoroutinePoolPtr pCoroutinePool = m_coroutinePool.lock();
	return pCoroutinePool->getMainCoroutineContext();
}

void Coroutine::run()
{
	if (nullptr != m_coroutineTask)
	{
		m_coroutineTask->run();
		m_coroutineTask = nullptr;
	}
}

void Coroutine::resetContext()
{
	unInitialize();
	initialize();
}
  • coroutine_pool.h
#pragma once
#ifndef __COROUTINE_POOL_H__
#define __COROUTINE_POOL_H__
#include "type.h"
#include "corountine.h"
class CoroutinePool: public std::enable_shared_from_this<CoroutinePool>
{
public:
	CoroutinePool(std::string coroutinePoolName);
	~CoroutinePool();
public:
	error_t initialize();

	error_t unInitialize();

	void clear();

	error_t addCoroutineTask(const CoroutineTaskPtr& coroutineTask);

	error_t resumeCoroutineTask(CoroutineId id, ResumeReason resumeReason);

	error_t yieldCoroutine(CoroutineId id);

	CoroutineId getCurrentCoroutineId();

	CoroutineContext getMainCoroutineContext();

	error_t moveRunningToSuspendCoroutine();

	error_t moveRunningToIdleCoroutine();

	error_t destroyCoroutine(CoroutineId coroutineId);

protected:

	CoroutineId getOneAvailableId();

	error_t createCoroutine();

private:
	std::map<CoroutineId, CoroutinePtr>    m_mapIdleCoroutines;
	std::map<CoroutineId, CoroutinePtr>    m_mapSuspendCoroutines;
	CoroutineId                            m_coroutineIndex; //记录分配的Id;
	std::string                            m_coroutinePoolName; // 协程池名称
	CoroutineContext                       m_coroutineMain;
	CoroutinePtr                           m_runningCoroutine;
};

using CoroutinePoolPtr = std::shared_ptr<CoroutinePool>;

#endif __COROUTINE_POOL_H__
  • coroutine_pool.cpp
#include "coroutine_pool.h"
#include "corountine.h"
#include "coroutine_common.h"
#ifdef PLATFORM_LINUX
#include <errno.h>
#endif

CoroutinePool::CoroutinePool(std::string coroutinePoolName) :
	m_mapIdleCoroutines(),
	m_mapSuspendCoroutines(),
	m_coroutineIndex(0),
	m_coroutinePoolName(coroutinePoolName),
	m_coroutineMain(nullptr),
	m_runningCoroutine(nullptr)
{

}

CoroutinePool::~CoroutinePool()
{
	clear();
}

error_t CoroutinePool::initialize()
{
#ifdef PLATFORM_WIN32
	m_coroutineMain = ConvertThreadToFiberEx(this, FIBER_FLAG_FLOAT_SWITCH);
#else
	m_coroutineMain = new ucontext_t();
	if (nullptr == m_coroutineMain) 
	{
		return -1}
	memset(m_coroutineMain, 0, sizeof(ucontext_t));
#endif
	return 0;
}

error_t CoroutinePool::unInitialize()
{
	clear();
#ifdef PLATFORM_WIN32
	if (0 == ConvertFiberToThread())
	{
		return -1;
	}
#else
	delete m_coroutineMain;
	m_coroutineMain = nullptr;
#endif
	return 0;
}

void CoroutinePool::clear()
{
	if (nullptr != m_runningCoroutine)
	{
		m_runningCoroutine.reset();
	}
	m_mapIdleCoroutines.clear();
	m_mapSuspendCoroutines.clear();
	m_runningCoroutine.reset();
	m_coroutineIndex = 0;
	m_coroutinePoolName = "";
}

error_t CoroutinePool::addCoroutineTask(const CoroutineTaskPtr& coroutineTask)
{
	//step1 参数校验
	error_t errorCode = 0;

	if (nullptr == coroutineTask)
	{
		errorCode = -1;
		return errorCode;
	}

	// step2 检查是否有空闲线程
	if (0 == m_mapIdleCoroutines.size())
	{
		if (0 != this->createCoroutine())
		{
			errorCode = -2;
			return errorCode;
		}
	}

	// step3 找到空闲协程,将任务分配给协程
	auto it = m_mapIdleCoroutines.begin();
	if (m_mapIdleCoroutines.end() != it)
	{
		CoroutinePtr coroutine = it->second;
		if (nullptr == coroutine)
		{
			errorCode = -3;
			return errorCode;
		}
		m_mapIdleCoroutines.erase(it);

		// step4 修改协程状态为running
		m_runningCoroutine = coroutine;
		errorCode = coroutine->setStatus(CoroutineStatusEnum::COROUTINE_STATUS_RUNNING);
		if (0 != errorCode)
		{
			return errorCode;
		}

		coroutineTask->setCoroutineId(coroutine->getCoroutineId());
		
		//step5 设置协程任务
		errorCode = coroutine->setCoroutineTask(coroutineTask);
		if (0 != errorCode)
		{
			return errorCode;
		}
	}
	return 0;
}

error_t CoroutinePool::resumeCoroutineTask(CoroutineId id, ResumeReason resumeReson)
{
	error_t errorCode = 0;
	//参数检验
	auto it = m_mapSuspendCoroutines.find(id);
	if (m_mapSuspendCoroutines.end() == it)
	{
		errorCode = 1;
		return errorCode;
	}

	CoroutinePtr coroutine = it->second;
	if (nullptr == coroutine)
	{
		errorCode = 2;
		return errorCode;
	}
	if (CoroutineStatusEnum::COROUTINE_STATUS_SUSPEND != coroutine->getStatus())
	{
		errorCode = 3;
		return errorCode;
	}

	// 从挂起中移除,设置为running
	m_mapSuspendCoroutines.erase(it);
	m_runningCoroutine = coroutine;
	coroutine->setStatus(CoroutineStatusEnum::COROUTINE_STATUS_RUNNING);
	coroutine->setResumeReason(resumeReson);

#ifdef PLATFORM_WIN32
	SwitchToFiber(coroutine->getContext());
#else
	getcontext(m_coroutineMain);
	swapcontext(m_coroutineMain, coroutine->getContext());
#endif
	return 0;
}

error_t CoroutinePool::yieldCoroutine(CoroutineId id)
{
	error_t errorCode = 0;
	// 参数检验
	if (nullptr == m_runningCoroutine)
	{
		errorCode = -11;
		return errorCode;
	}
	if (m_runningCoroutine->getCoroutineId() != id)
	{
		errorCode = -12;
		return errorCode;
	}
	moveRunningToSuspendCoroutine();

	//切回主协程
#ifdef PLATFORM_WIN32
	SwitchToFiber(m_coroutineMain);
#else
	swapcontext(m_runningCoroutine->getContext(), m_coroutineMain);
#endif
	// 从这里恢复
	ResumeReason resumeReason = m_runningCoroutine->getResumeReason();
	switch (resumeReason) 
	{
	case ResumeReason::REASON_NORMAL:
	{
		return 0;
	}
	case ResumeReason::REASON_ERROR:
	{
		return -100;
	}
	case ResumeReason::REASON_TIME_OUT:
	{
		return -101;
	}
	default:
		break;
	}
	return -1;
}

CoroutineId CoroutinePool::getCurrentCoroutineId()
{
	if (nullptr == m_runningCoroutine)
	{
		return -1;
	}
	return m_runningCoroutine->getCoroutineId();
}

CoroutineContext CoroutinePool::getMainCoroutineContext()
{
	if (nullptr == m_coroutineMain)
	{
		return nullptr;
	}
	return m_coroutineMain;
}

error_t CoroutinePool::moveRunningToSuspendCoroutine()
{
	if (nullptr == m_runningCoroutine)
	{
		return -1;
	}
	if (m_mapSuspendCoroutines.end() != m_mapSuspendCoroutines.find(m_runningCoroutine->getCoroutineId()))
	{
		return -2;
	}

	m_mapSuspendCoroutines[m_runningCoroutine->getCoroutineId()] = m_runningCoroutine;
	m_runningCoroutine->setStatus(CoroutineStatusEnum::COROUTINE_STATUS_SUSPEND);
	return 0;
}

error_t CoroutinePool::moveRunningToIdleCoroutine()
{
	if (nullptr == m_runningCoroutine)
	{
		return -1;
	}
	if (m_mapIdleCoroutines.end() != m_mapIdleCoroutines.find(m_runningCoroutine->getCoroutineId()))
	{
		return -2;
	}

	m_mapIdleCoroutines[m_runningCoroutine->getCoroutineId()] = m_runningCoroutine;
	m_runningCoroutine->setStatus(CoroutineStatusEnum::COROUTINE_STATUS_IDLE);
	return 0;
}

error_t CoroutinePool::destroyCoroutine(CoroutineId coroutineId)
{
	error_t errorCode = 0;
	// 当前跑的协程直接销毁
	if (nullptr != m_runningCoroutine && m_runningCoroutine->getCoroutineId() == coroutineId)
	{
		moveRunningToIdleCoroutine();
		m_runningCoroutine->resetContext();
		return errorCode;
	}
	// 对于在supspend状态的协程处理
	auto it = m_mapSuspendCoroutines.find(coroutineId);
	if (m_mapSuspendCoroutines.end() == it || nullptr == it->second)
	{
		errorCode = -201;
		return errorCode;
	}
	CoroutinePtr coroutine = it->second;
	m_mapSuspendCoroutines.erase(it);
	coroutine->setStatus(CoroutineStatusEnum::COROUTINE_STATUS_IDLE);
	if (m_mapIdleCoroutines.end() == m_mapIdleCoroutines.find(coroutineId))
	{
		m_mapIdleCoroutines[coroutine->getCoroutineId()] = coroutine;
	}
	coroutine->resetContext();
	return errorCode;
}

error_t CoroutinePool::createCoroutine()
{
	error_t errorCode = 0;
	//创建协程
	
	CoroutinePtr coroutine(new Coroutine(getOneAvailableId(), shared_from_this()));

	if (nullptr == coroutine)
	{
		errorCode = 301;
		return errorCode;
	}
	//初始化协程
	errorCode = coroutine->initialize();
	if (0 != errorCode)
	{
		return errorCode;
	}
	//加入空闲队列
	coroutine->setStatus(CoroutineStatusEnum::COROUTINE_STATUS_IDLE);
	m_mapIdleCoroutines[coroutine->getCoroutineId()] = coroutine;
	return errorCode;
}

CoroutineId CoroutinePool::getOneAvailableId()
{
	return ++m_coroutineIndex;
}
  • coroutine_common
#pragma once
#ifndef __COROUTINE_COMMON__
#define __COROUTINE_COMMON__
#include "type.h"

#define IN
#define OUT
#define INIT_STACK 1048576

#ifdef PLATFORM_WIN32
	typedef void* CoroutineContext;
#else
typedef ucontext_t* CoroutineContext
#endif

typedef signed int CoroutineId;
enum class CoroutineStatusEnum: int
{
	COROUTINE_STATUS_DEAD = 0,
	COROUTINE_STATUS_IDLE,
	COROUTINE_STATUS_READY,
	COROUTINE_STATUS_RUNNING,
	COROUTINE_STATUS_SUSPEND,
	COROUTINE_STATUS_UNKNOWN,
	COROUTINE_STATUS_NOTFOUNT,
};

enum class ResumeReason :int
{
	REASON_TIME_OUT = 0,
	REASON_NORMAL,
	REASON_ERROR,
};

#endif __COROUTINE_COMMON__
  • coroutine_task.h
#pragma once
#ifndef __COROUTINE_TASK__
#define __COROUTINE_TASK__
#include "coroutine_common.h"

enum class EnumTaskStatus :int
{
	TASK_STATUS_UNFINISH = 0,
	TASK_STATUS_ERROR,
	TASK_STATUS_FINISH
};

class CoroutineTask
{
public:
	CoroutineTask() {};
	virtual ~CoroutineTask() = default;
public:
	EnumTaskStatus getTaskStatus() const { return m_status; };

	void setCoroutineId(CoroutineId coroutineId) { m_coroutineId = coroutineId; };

	CoroutineId getCoroutineId() const { return m_coroutineId; };

	virtual void run() = 0;
protected:
	CoroutineId      m_coroutineId;
	EnumTaskStatus   m_status;
};

using CoroutineTaskPtr = std::shared_ptr<CoroutineTask>;

#endif __COROUTINE_TASK__
  • count.h
#pragma once
#ifndef _COUNT_TASK__
#define _COUNT_TASK__
#include "coroutine_task.h"
class TaskCount : public CoroutineTask
{
public:
	TaskCount(int from, int to)
	{
		m_from = from;
		m_to = to;
	};
	void run()
	{
		for (int i = m_from; i < m_to; ++i)
		{
			std::cout << i << " ";
		}
	}
private:
	int m_from;
	int m_to;
};
#endif
  • type.h

#ifndef __BASIC_TYPE__
#define __BASIC_TYPE__

typedef unsigned int error_t;
#include <iostream>
#include <map>
#include <string>
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
#ifndef PLATFORM_WIN32
#define PLATFORM_WIN32
#include <windows.h>
#endif
#else
#ifndef PLATFORM_LINUX
#define PLATFORM_LINUX
#include <ucontext.h>
#endif
#endif
#endif __BASIC_TYPE__
  • main.cpp
#include "coroutine_pool.h"
#include "count.h"
int main()
{
	// 初始化协程池
	CoroutinePoolPtr pCoroutinePool(new CoroutinePool("first"));
	pCoroutinePool->initialize();
	// 创建协程执行任务,并添加该任务
	CoroutineTaskPtr task(new TaskCount(0, 10));
	pCoroutinePool->addCoroutineTask(task);
	return 0;
}

版权声明:本文为weixin_43804370原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。