协程,也叫微线程,多个协程在逻辑上是并发的,实际并发由用户控件。
在windows上引入了纤程(fiber)。
WinBase.h 中函数原型
#if(_WIN32_WINNT >= 0x0400)
//
// Fiber begin
//
#pragma region Application Family or OneCore Family or Games Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
#define FIBER_FLAG_FLOAT_SWITCH 0x1 // context switch floating point
WINBASEAPI
VOID
WINAPI
SwitchToFiber(
_In_ LPVOID lpFiber
);
WINBASEAPI
VOID
WINAPI
DeleteFiber(
_In_ LPVOID lpFiber
);
#if (_WIN32_WINNT >= 0x0501)
WINBASEAPI
BOOL
WINAPI
ConvertFiberToThread(
VOID
);
#endif
WINBASEAPI
_Ret_maybenull_
LPVOID
WINAPI
CreateFiberEx(
_In_ SIZE_T dwStackCommitSize,
_In_ SIZE_T dwStackReserveSize,
_In_ DWORD dwFlags,
_In_ LPFIBER_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter
);
WINBASEAPI
_Ret_maybenull_
LPVOID
WINAPI
ConvertThreadToFiberEx(
_In_opt_ LPVOID lpParameter,
_In_ DWORD dwFlags
);
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) */
#pragma endregion
#pragma region Desktop Family or OneCore Family or Games Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
WINBASEAPI
_Ret_maybenull_
LPVOID
WINAPI
CreateFiber(
_In_ SIZE_T dwStackSize,
_In_ LPFIBER_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter
);
WINBASEAPI
_Ret_maybenull_
LPVOID
WINAPI
ConvertThreadToFiber(
_In_opt_ LPVOID lpParameter
);
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) */
#pragma endregion
//
// Fiber end
//
一个简单的例子
#include <iostream>
#include <Windows.h>
LPVOID mainFiber,workFiber;
int i;
void fiberProc(LPVOID lpFiberParameter)
{
for(i = 0;i < 10; ++i)
{
SwitchToFiber(mainFiber);
}
}
int main(int argc,char** argv,char** env)
{
mainFiber = ConvertThreadToFiber(NULL);
workFiber = CreateFiber(1024,fiberProc,NULL);
SwitchToFiber(workFiber);
std::cout << i << std::endl;
SwitchToFiber(workFiber);
std::cout << i << std::endl;
DeleteFiber(workFiber);
ConvertFiberToThread();
return 0;
}
windows 上Fiber的调度需要用户自己控制
简单做一个协程调度
#include <iostream>
#include <Windows.h>
#include <list>
#include <functional>
using co_proc = std::function<void(void*)>;
void __co_proc(LPVOID lpParam);
static int ids = 0;
class scheduler;
class corountine
{
public:
co_proc proc_;
void* param_;
corountine(co_proc proc,void* param)
:proc_(proc), param_(param),isfinished(false),id(++ids)
{
this->fiber = CreateFiber(1024,__co_proc,this);
}
virtual ~corountine()
{
DeleteFiber(this->fiber);
}
LPVOID fiber;
bool isfinished;
int id;
scheduler* sch;
};
class scheduler
{
std::list<corountine*> cos_;
public:
scheduler()
{
mainFiber = ConvertThreadToFiber(NULL);
}
virtual ~scheduler()
{
ConvertFiberToThread();
}
void push_corountine(corountine* co)
{
co->sch = this;
cos_.push_back(co);
}
void run()
{
while(!cos_.empty()) {
auto* co = cos_.front();
cos_.erase(cos_.begin());
if (!co->isfinished) {
SwitchToFiber(co->fiber);
}
if (!co->isfinished) {
cos_.push_back(co);
} else {
delete co;
}
}
}
void yield()
{
SwitchToFiber(mainFiber);
}
LPVOID mainFiber;
};
void __co_proc(LPVOID lpParam)
{
corountine* co = (corountine*)lpParam;
co->isfinished = false;
co->proc_(co->param_);
co->isfinished = true;
SwitchToFiber(co->sch->mainFiber); // 一定要加上这句,不然主线程会结束
}
int main(int argc,char** argv,char** env)
{
scheduler sch;
sch.push_corountine(new corountine([&](void* p){
for (int i = 0;i < 7; ++i)
{
std::cout << "i:"<<i<<std::endl;
sch.yield();
}
},nullptr));
sch.push_corountine(new corountine([&](void* p){
for (int j = 0;j < 4; ++j)
{
std::cout << "j:"<<j<<std::endl;
sch.yield();
}
},nullptr));
sch.run();
return 0;
}