首页 > 编程语言 > 详细

C++ Win32纤程的简单使用示例

时间:2021-04-16 09:17:49      阅读:31      评论:0      收藏:0      [点我收藏+]

文档

https:docs.microsoft.com/en-us/windows/win32/procthread/fibers

 

 

简要讲解

纤程也是一个执行上下文,比如各个寄存器的值

只不过纤程是由用户层面决定调度的

线程可以被转换为纤程,也就是创建纤程上下文,这样才能进行纤程之间的切换,也就是把当前上下文保存起来去执行另一个上下文

纤程只能由纤程去调度,也就是拥有纤程上下文的执行实体把当前纤程上下文保存,然后装上另一个纤程上下文执行

假如拥有执行实体的纤程自己删自己会导致执行实体退出

纤程上下文的起始方法退出,那么执行实体就会退出,但是该纤程上下文还有没有效不太清楚,按道理讲指令指针寄存器可能已经指向了非用户代码了,就跟main方法返回了差不多

拥有执行实体的纤程上下文自己调度自己的行为未定义

 

要注意的地方

当你删除一个纤程上下文的时候,该纤程的栈会直接释放,假如你的栈中存在未析构的智能指针或者未析构的对象,那么会造成资源泄露

假如你要使用DeleteFiber函数删除纤程,那么纤程方法永远不会正常退出,它的生命结束于SwitchToFiber函数的调用永远不会再返回,意思就是你调用SwitchToFiber函数把上下文切换,执行实体换上另一个上下文,然后把原先的上下文也就是纤程删了,那被删除的上下文中的SwitchToFiber函数调用肯定永远不会返回。纤程方法指的是你创建纤程时传入的那个

 

 

简单示例

示例一

示例开头的代码是用来本地化错误代码的,跟主体没有关系

主要逻辑在main方法中

我把本机接口简单包装了一下,所以是通过Fiber类来进行调用

#include <iostream>
#include <windows.h>



std::string GetWin32ErrorMessage(DWORD errorCode) {

    char buffer[4096];

    auto length = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, errorCode, 0, buffer, sizeof(buffer), nullptr);

    return std::string{ buffer, length };
}

void Exit(const std::string& message, DWORD errorCode) {
    std::cout << message << "    " << GetWin32ErrorMessage(errorCode) << std::endl;
    exit(errorCode);
}

void Exit(const std::string& message) {
    Exit(message, GetLastError());
}



void Print() {
    std::cout << std::endl;
}


template<typename T, typename ...TS>
void Print(T value, TS ...values) {
    std::cout << value << "   ";
    Print(values...);
}



class Fiber {

public:
    static LPVOID ConvertToFiber() {
        auto handle = ::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);

        if (handle == nullptr) {
            Exit("Convert To Fiber Error");
        }
        
        return handle;
    }

    
    static void ConvertToThread() {

        if (::ConvertFiberToThread() == 0) {
            Exit("Convert To Thread Error");
        }
    }


    static auto GetCurrentFiber() {

        return ::GetCurrentFiber();
    }

    static LPVOID Create(LPFIBER_START_ROUTINE func) {

        auto handle = ::CreateFiberEx(0, 0, FIBER_FLAG_FLOAT_SWITCH, func, Fiber::GetCurrentFiber());

        if (handle == nullptr) {
            Exit("Create Fiber Error");
        }

        return handle;
    }


    static void Switch(LPVOID fiber) {
        if (fiber == Fiber::GetCurrentFiber()) {
            Exit("Switch Fiber error");
        }

        ::SwitchToFiber(fiber);
    }

    static void Delete(LPVOID fiber) {
        
        ::DeleteFiber(fiber);
    }
};



int main() {


    auto one_fiber = Fiber::ConvertToFiber();


    auto tow_fiber = 
        Fiber::Create([](auto create_fiber) {
        
            Print("子纤程运行");

            Fiber::Delete(Fiber::GetCurrentFiber());    

            while (true)
            {
                Fiber::Switch(create_fiber);
                
                Print("子纤程运行");
            }    
        });


    Print("已经创建了子纤程,但未运行");


    Fiber::Switch(tow_fiber);
    Print("子纤程,调度回来啦");
    
    Fiber::Switch(tow_fiber);
    Print("子纤程,调度回来啦");
    
    Fiber::Switch(tow_fiber);
    Print("子纤程,调度回来啦");



    Fiber::Delete(tow_fiber);



    Fiber::ConvertToThread();


}

 示例二

利用纤程与io完成端口写的一个简单的文件服务器

https://github.com/LeiKaiFeng-GoodBoy/CppHttpFileServer

 

C++ Win32纤程的简单使用示例

原文:https://www.cnblogs.com/leikaifeng/p/14665337.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!