windows C++ Fiber (协程)
协程,也叫微线程,多个协程在逻辑上是并发的,实际并发由用户控件。
在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 pointWINBASEAPI
VOID
WINAPI
SwitchToFiber(_In_ LPVOID lpFiber);WINBASEAPI
VOID
WINAPI
DeleteFiber(_In_ LPVOID lpFiber);#if (_WIN32_WINNT >= 0x0501)WINBASEAPI
BOOL
WINAPI
ConvertFiberToThread(VOID);#endifWINBASEAPI
_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;}