Drecik学习经验分享
转载请注明出处:http://blog.csdn.net/drecik__/article/details/8202023
Windows提供纤程是为了帮助各个公司更快地、正确地将它们的代码从UNIX移植到Windows中。
但我们要记住,自己在Windows上设计程序时,应该避免使用纤程,而使用Windows提供的线程机制。
首先要了解的是,纤程是在用户模式下实现的,内核对纤程一无所知,内核会根据我们定义的算法来对纤程进行调度。
一个线程可以包含一个或多个纤程。对内核而言它会对线程进行抢占式调度来让线程执行代码,但是,线程一次只能执行一个纤程代码(由我们决定哪个纤程)。
使用纤程的步骤:
通过函数ConvertThreadToFiber将一个已有的线程转化为一个纤程:
LPVOID // 返回纤程执行上下文的地址; ConvertThreadToFiber( LPVOID lpParameter );
该函数会创建一个纤程的执行上下文,有下面元素构成:
默认情况下CPU浮点状态信息不属于CPU寄存器一部分,不会每个纤程都维护一份,如果纤程需要执行浮点操作,则需要使用函数ConvertThreadToFiberEx来转换:
- 一个用户自定义的值,即传入的lpParameter参数
- 结构化异常处理链的头
- 纤程栈的顶部和底部的内存地址
- 某些CPU寄存器,其中包括栈指针,指令指针以及其他寄存器
LPVOID ConvertThreadToFiberEx( LPVOID lpParameter, DWORD dwFlags // 传入FIBER_FLAG_FLOAT_SWITCH标志; );
除非打算创建更多的纤程,并让它们在同一个线程中运行,否则没有理由将一个线程转换为纤程,创建另一个纤程,当前线程使用CreateFiber或CreateFiberEx:
LPVOID // 返回纤程执行上下文的地址; CreateFiber( SIZE_T dwStackSize, // 栈大小,通常为0; LPFIBER_START_ROUTINE lpStartAddress, // 指定纤程函数的地址; LPVOID lpParameter // 用户自定义值,会保存到纤程执行上下文; ); LPVOID CreateFiberEx( SIZE_T dwStackCommitSize, // 指定一开始要调拨的物理存储页; SIZE_T dwStackReserveSize, // 预定指定数量的虚拟内存; DWORD dwFlags, // 可以指定需要进行浮点操作,传入FIBER_FLAG_FLOAT_SWITCH标志; LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ); // 纤程函数的函数原型; // 该函数不应该返回,如果返回,该线程以及它创建的所有纤程都会立即被销毁; typedef VOID (WINAPI *PFIBER_START_ROUTINE)( LPVOID lpFiberParameter // 传入用户自定义的值; );
CreateFiber(Ex)与ConvertTreadToFiber(Ex)不同之处在于,它创建的纤程不会立即执行,因为当前运行的纤程还在执行,在同一时刻只能执行一个纤程,可以使用SwitchToFiber来让新的纤程执行:
VOID SwitchToFiber( LPVOID lpFiber // 纤程执行上下文地址; );
在内部该函数会将正在执行的纤程CPU寄存器保存起来在执行上下文中,然后将要执行纤程的CPU寄存器载入到CPU中,并将新的纤程与线程关联,让线程运行指定的纤程,最后就是载入指令指针,让纤程从上次运行的地方开始执行。
最后可以调用DeleteFiber啦销毁纤程:
VOID DeleteFiber( LPVOID lpFiber // 纤程执行上下文地址; );
函数会删除该参数标识的纤程,并释放线程的栈并销毁纤程的执行上下文,如果该纤程与线程正在关联,则会在内部调用ExitThread,从而使线程以及为它创建的纤程都结束。
DeleteFiber通常为一个纤程调用,以删除另一个纤程,与线程不同,线程是最好不要终止另外一个线程。
当所有纤程都被删除,可以调用ConvertFiberToThread(Ex)来解除线程的纤程状态,同时释放最后一块内存块。
如果想知道当先的线程相关联的纤程地址,可以调用GetCurrentFiber,也可以调用GetFiberData返回用户自定义的值。