概念
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;
}