[笔记]Windows核心编程《十二》纤程

系列文章目录

[笔记]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核心编程《二十三》结构化异常处理

前言

目的:
为了更容易将已有的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示例程序

相关:

参考1
参考2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二进制怪兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值