Windows下 纤程/协程

  • 理论知识,立足根本
  • 使用须知
  • 代码

写这篇文章的原因是,很多框架/库都有协程/纤程的支持,比如python的gevent,PHP 的swoole等等,但是具体是什么样的呢?为什么协程方式性能会更好?很多初学者听个词,听风就是雨,把协程和IO能混成一个概念。

理论知识,立足根本

在Windows2000 / XP中,纤程(fiber)相当于用户级别的线程或轻进程.纤程由Win32库函数支持, 对核心是不可见的.纤程可以通过SwitchToFiber显示至另一合作纤程, 以实现合作纤程之间的协同.
纤程包含独立的目态栈, 寄存器状态的控制信息.目态控制的纤程转接要求较高的编程经验.由于纤程属于目态对象, 一个纤程被封锁意味着所在线程被封锁.应用程序可以通过ConvertThreadToFiber将线程转换为纤程.与线程对比, 纤程具有切换速度快的特点.
Microsoft公司给Windows添加了一种纤程,以便能够非常容易地将现有的UNIX服务器应用程序移植到Windows中。UNIX服务器应用程序属于单线程应用程序(由Windows定义),但是它能够为多个客户程序提供服务。换句话说, UNIX应用程序的开发人员已经创建了他们自己的线程结构库,他们能够使用这种线程结构库来仿真纯线程。该线程包能够创建多个堆栈,保存某些C P U寄存器,并且在它们之间进行切换,以便为客户机请求提供服务。
显然,若要取得最佳的性能,这些UNIX应用程序必须重新设计,仿真的线程库应该用Windows提供的纯线程来替代。然而,这种重新设计需要花费数月甚至更长的时间才能完成,因此许多公司首先将它们现有的UNIX代码移植到Windows中,这样就能够将某些应用软件推向Windows市场。
而协程性能比线程更好的主要原因在于:

  • 线程是在系统内核中实现的,纤程是在用户模式下实现的,内核对纤程一无所知,内核会根据我们定义的算法来对纤程进行调度。
    一个线程可以包含一个或多个纤程。

使用须知

使用纤程的第一个步骤是将已有的线程转换为一个纤程。ConvertThreadToFiber这个函数会为纤程的上下文分配内存,这个上下文的构成是:

  • 一个用户自定义的值
  • 结构化异常处理链的头
  • 纤程栈的顶部和底部的内存地址
  • 某些CPU寄存器,其中包括栈指针、指令指针以及其他寄存器

当我们分配了纤程执行上下文并对其进行初始化之后,还必须将执行上下文的地址与线程关联起来。这样我们就将线程转换成了一个纤程,该纤程在这个线程中执行。
其实,除非我们打算创建更多的纤程,并让它们在同一个线程中运行,否则没有理由将一个线程转换为纤程。

  1. 使用ConverThreadToFiber(Ex)将当前线程转换到纤程,这是纤程F1
    这里说一下ConverThreadToFiber和ConverThreadToFiberEx的区别
    ConverThreadToFiber这个函数会为纤程的执行上下文分配(大约200个字节)的内存,这个执行上下文由下列元素构成:
    ·一个用户自定义的值,它被初始化给ConverThreadToFiber的pvParam参数。
    ·结构化异常处理链的头
    ·纤程栈的顶部和底部的内存地址(当我们将一个线程转换为一个纤程的时候,这同时也是线程栈)
    ·某些CPU寄存器,其中包括栈指针,指令指针以及其他寄存器
    默认情况下x86系统中,CPU的浮点信息不属于CPU寄存器的一部分,不会每个纤程都维护一份,因此如果纤程需要执行浮点操作,那将会导致数据被破坏。
    为了覆盖系统默认的行为,我们应该调用新的ConverThreadToFiberEx函数,它允许我们在dwFlags参数中传入FIBER_FLAG_FLOAT_SWITCH标志
  1. 定义一个纤程函数,用于创建一个新纤程
  1. 纤程F1中调用CreateFiber(Ex)函数创建一个新的纤程F2
  1. SwitchToFiber函数进行纤程切换,让新创建的纤程F2执行
  1. F2纤程函数执行完毕的时候,使用SwitchToFiber转换到F1
  1. 在纤程F1中调用DeleteFiber来删除纤程F2
  1. 纤程F1中调用ConverFiberToThread,转换为线程
  1. 线程结束

代码


#include "pch.h"
#include <iostream>
#include <windows.h>
#include <tchar.h>
#define FIBER_COUNT 2
LPVOID g_lpFiber[FIBER_COUNT] = {};
VOID WINAPI FiberFun(LPVOID pParam) //纤程函数的返回类型为VOID,并不是因为返回值没有意义,而是因为这个函数不应该返回!如果纤程函数返回,那么该线程以及它所创建的所有纤程都将立即被销毁
{LPCTSTR szParam1 = (LPCTSTR)pParam;LPCTSTR szparam2 = (LPCTSTR)GetFiberData();TCHAR szMsg[100] = { 0 };_stprintf_s(szMsg, TEXT("参数1:%s, 参数2:%s。\n"), szParam1, szparam2);//szParam1和szparam2一样的//OutputDebugString(szMsg);std::wcout.imbue(std::locale("", LC_CTYPE));std::wcout << szMsg;SwitchToFiber(g_lpFiber[0]);//必须切换回主线程程序才能继续执行,不然会卡在这里程序无法退出
}int main()
{g_lpFiber[0] = ConvertThreadToFiber((LPVOID)_T("我是ConvertThreadToFiber的参数\n"));g_lpFiber[1] = CreateFiber(0, FiberFun, (LPVOID)_T("我是纤程的参数"));SwitchToFiber(g_lpFiber[1]);//切换到g_lpFiber[1]LPCTSTR szParam = (LPCTSTR)GetFiberData();std::wcout.imbue(std::locale("", LC_CTYPE));std::wcout << szParam;BOOL bCftt = ConvertFiberToThread();//转回线程if (bCftt) {DeleteFiber(g_lpFiber[1]);}std::cout << "Hello World!\n";
}

我们完全可以在IO多路复用中使用协程,让我们自己定义如何调度这些方法。

Windows 纤程/协程相关推荐

  1. Kotlin协程 - - - 协程的简单使用

    一.协程介绍 1.简介 协程是一种并发设计模式,您可以在 Android 平台上使用它来简化异步执行的代码.协程是在版本 1.3 中添加到 Kotlin 的,它基于来自其他语言的既定概念. 在 And ...

  2. 进程 线程 协程_进程 线程 协程 管程 纤程 概念对比理解

    不知道是不是我自己本身就有那么一丝丝的密集恐惧,把这么一大堆看起来很相似很相关的概念放在一起,看起来是有点麻,捋一捋感觉舒服多了. 相关概念 任务.作业(Job,Task,Schedule) 在进程的 ...

  3. Thread(线程)、Fiber(纤程)、coroutine(协程) 、绿色线程(GreenThread)

    计算机有进程,线程和协程.前两者大家都知道,很常见的玩意.而协程,则是基于线程之上的,自主开辟的异步任务,很多人更喜欢叫它们纤程(Fiber),或者绿色线程(GreenThread). 进程 为了使多 ...

  4. Day10-Python3基础-协程、异步IO、redis缓存、rabbitMQ队列

    内容目录: Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko S ...

  5. python进程\协程\异步IO

    进程 学习python中有什么不懂的地方,小编这里推荐加小编的python学习群:895 817 687有任何不懂的都可以在里面交流,还有很好的视频教程pdf学习资料,大家一起学习交流! Python ...

  6. python异步和进程_12.python进程\协程\异步IO

    进程 Python中的多线程无法利用多核优势 , 所以如果我们想要充分地使用多核CPU的资源 , 那么就只能靠多进程了 multiprocessing模块中提供了Process , Queue , P ...

  7. Python 异步 IO 、协程、asyncio、async/await、aiohttp

    From :廖雪峰 异步IO :https://www.liaoxuefeng.com/wiki/1016959663602400/1017959540289152 Python Async/Awai ...

  8. linux的进程/线程/协程系列5:协程的发展复兴与实现现状

    协程的发展复兴与实现现状 前言 本篇摘要: 1. 协同制的发展史 1.1 协同工作制的提出 1.2 自顶向下,无需协同 1.3 协同式思想的应用 2. 协程的复兴 2.1 高并发带来的问题 2.2 制 ...

  9. 进程,线程和协程 并行与并发

    一.进程 进程的出现是为了更好的利用CPU资源使到并发成为可能. 假设有两个任务A和B,当A遇到IO操作,CPU默默的等待任务A读取完操作再去执行任务B,这样无疑是对CPU资源的极大的浪费.聪明的老大 ...

最新文章

  1. 一个页面多个swiper问题解决
  2. mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比,于是写了个插件。
  3. PyQt5 关于自动补全 QCompleter
  4. 超400万用户的Chrome截图插件下架始末
  5. AcWing 841. 字符串哈希(字符串Hash)
  6. 《 Programming Collective Intelligence》案例介绍与分析——Making Recommendations
  7. 60行C代码的shell领略Unix哲学之美
  8. 0-1整数规划的求解思路整理
  9. 不堪回首的真实往事:我和一个骗子网友的两年矛盾纠葛
  10. Tik Tok直播:如何做好TikTok直播?
  11. 如果有一天我不更新博客了
  12. 重要的不是你正在做什么,而是你在想什么
  13. 辰视将携3D视觉技术及各领域解决方案参加华南工博会国际机器视觉展
  14. 【LaTeX】IEEE会议模板中插入双栏图片(解决报错:Undefined control sequence. \subfloat
  15. 素材管理神器 Eagle 下载安装使用教程
  16. 辣味人生:享受有辣而不辣
  17. 在职人员如何发表期刊论文
  18. word 参考文献 交叉引用 自动更新
  19. 北大软微计算机应用基础真题,北京大学软微考研参考书、考研真题及复习经验...
  20. dao层(dao层的作用)

热门文章

  1. 2022/04/29 第一次晋升答辩总结
  2. 理论+实操:K8S搭建dns内部服务与控制器controlls五种模式
  3. 迁移学习---举一反三
  4. thunderbird收件箱只显示邮件个数,无法打开邮件
  5. SpingBoot—微服务初始化资源方法
  6. 低密度奇偶校验码(LDPC)
  7. 【JavaSE系列】世界上“最好的语言”——认识Java编程语言
  8. Win7下SQLite安装配置与使用方法详解
  9. 程序员抛弃大厂涌进工厂!南洋理工海归:这里上班比整天盯着电脑有意思的多!...
  10. 项目学习 —— 图书商城后台管理