系列文章目录
[笔记]Windows核心编程《一》错误处理、字符编码
[笔记]Windows核心编程《二》内核对象
[笔记]Windows核心编程《三》进程
[笔记]Windows核心编程《四》作业
[笔记]快乐的LInux命令行《五》什么是shell
[笔记]Windows核心编程《五》线程基础
[笔记]Windows核心编程《六》线程调度、优先级和关联性
[笔记]Windows核心编程《七》用户模式下的线程同步
[笔记]Windows核心编程《八》用内核对象进行线程同步
[笔记]Windows核心编程《九》同步设备I/O和异步设备I/O
[笔记]Windows核心编程《十一》Windows线程池
[笔记]Windows核心编程《十二》纤程
[笔记]Windows核心编程《十三》windows内存体系结构
[笔记]Windows核心编程《十四》探索虚拟内存
[笔记]Windows核心编程《十五》在应用程序中使用虚拟内存
[笔记]Windows核心编程《十六》线程栈
[笔记]Windows核心编程《十七》内存映射文件
[笔记]Windows核心编程《十八》堆栈
[笔记]Windows核心编程《十九》DLL基础
[笔记]Windows核心编程《二十》DLL的高级操作技术
[笔记]Windows核心编程《二十一》线程本地存储器TLS
[笔记]Windows核心编程《二十二》注入DLL和拦截API
[笔记]Windows核心编程《二十三》结构化异常处理
文章目录
系列文章目录
前言
使用纤程
将一个已有的线程转换为一个纤程
一个已有的线程转换为一个纤程
在当前线程中创建另一个纤程
需要调用SwitchToFiber来切换纤程
调用DeleteFiber来销毁纤程
获得纤程执行的上下文
返回纤程的用户自定义值(CreateFiber所传递的pvParam)
Counter示例程序
前言
目的:
为了更容易将已有的UNIX服务器应用迁移到Windows,增加了纤程。
UNIX应用程序的开发人员创建了线程包,来实现类似线程功能。
使用纤程
- 线程在windows内核中实现的。
- 纤程是在用户模式下实现的。
- 内核仅能调度线程,而纤程由我们调度
- 一个线程可包含多个纤程。
将一个已有的线程转换为一个纤程
一个已有的线程转换为一个纤程
PVOID ConvertThreadToFiber(PVOID pvParam);
如果函数成功,返回值是纤维的地址;如果函数失败,返回值是零。
这个函数为纤程的执行上下文CONTEXT分配内存。
执行上下文一般包含:
一个用户自定义的值(pvParam)
结构化异常处理链的头
纤程栈的顶部和底部的内存地址
某些CPU寄存器,包括栈指针,指令指针以及其他寄存器
默认情况下x86系统中CPU的浮点状态信息不属于CPU寄存器的一部分,不会为每个纤程都维护一份,而如果纤程要执行浮点操作,那会导致数据被破坏。
为了覆盖系统的默认行为需要使用新的ConvertThreadToFiberEx函数
允许传入FIBER_FLAG_FLOAT_SWITCH标志:
WINBASEAPI _Ret_maybenull_ LPVOID WINAPI ConvertThreadToFiberEx( _In_opt_ LPVOID lpParameter, _In_ DWORD dwFlags );
除非打算在一个线程中执行多个纤程,否则只为执行一个任务,而将线程转换为纤程没有任
在当前线程中创建另一个纤程
WINBASEAPI _Ret_maybenull_ LPVOID WINAPI CreateFiber( _In_ SIZE_T dwStackSize, _In_ LPFIBER_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter );
如果要使用大量的纤程,希望纤程消耗更少的内存使用下列函数来创建纤程。
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 );
dwStackCommitSize:设置一开始要调拨的物理存储页。
dwStackReservesize: 运行我们预定指定的虚拟内存。
dwFlags:可以接受FIBER_FLAG_FLOAT_SWITCH将浮点运算状态保留。
lpfnStartAddress:用来指定纤程函数的地址。例如以下就是定义一个纤程函数。
VOID WINAPI FiberFunc(PVOID pvParam);
其他参数和CreateFiber相同。
CreateFiber返回的是为纤程创建的CONTEXT的地址(和ConvertThreadToFiber类似)
但是CreateFiber创建的新纤程默认不会执行。(因为一个线程中只能执行一个纤程)
需要调用SwitchToFiber来切换纤程
WINBASEAPI VOID WINAPI SwitchToFiber( _In_ LPVOID lpFiber );
lpFiber是用CreateFiber或ConvertThreadToFiber返回的值,告诉函数要调用哪个纤程。SwitchToFiber会执行以下步骤:
1)将一些cpu寄存器目前的值,其中包括指令指针(IP)寄存器和栈指针寄存器(SP) 保存在当前运行的纤程的CONTEXT中
2)从即将运行的纤程的执行CONTEXT中载入先前保存的寄存器值并载入cpu
这些寄存器中包含栈指针寄存器,这样单线程继续执行就会使用新纤程的栈。
3)将新纤程的执行CONTEXT和线程关联,让线程运行指定的纤程。
4)将线程的指令指针设为先前保存的指令指针(IP),这样线程(纤程)就会从上次执行的地方开始继续往下执行。
SwitchToFiber是让纤程得到cpu时间切片的唯一方法。所以纤程的调度完全由我们自己掌控。
调用DeleteFiber来销毁纤程
WINBASEAPI VOID WINAPI DeleteFiber( _In_ LPVOID lpFiber );
lpFiber是纤程的CONTEXT地址。该函数会删除参数所表示的纤程。如果线程和纤程绑定了,其内部会调用ExitThread同时销毁当前的线程。
(TerminateThread不会销毁线程栈)
将转成了纤程的线程转回来。
ConvertTiberToThread(Ex)
如果为纤程保存一些信息可以使用纤程局部存储区(Fiber Local Storage, FLS)函数
其他纤程相关的函数
获得纤程执行的上下文
PVOID GetCurrentFiber();
返回纤程的用户自定义值(CreateFiber所传递的pvParam)
PVOID GetFiberData();
Counter示例程序
相关: