第12章 纤程(Fiber)

时间:2022-09-22 11:12:19

12.1 纤程对象的介绍

(1)纤程与线程的比较

比较

线程(Thread)

纤程(Fiber)

实现方式

是个内核对象

在用户模式中实现的一种轻量级的线程,是比线程更小的调度单位。

调度方式

由Microsoft定义的算法来调度,操作系统对线程了如指掌。内核对线程的调度是抢占式的。

由我们自己调用SwitchToFiber来调度,内核对纤程一无所知。线程一次只能执行一个纤程代码,纤程间的调度不是抢占式的。

备注

一个线程可以包含一个或多个纤程。操作系统随时可能夺走纤程所在线程的运行。当线程被调度时,当前被选择的纤程得以运行,而其他纤程无法运行,因为同一个线程中,每次只能有一个纤程正在运行,除非调用SwitchToFiber才能切换到另一个纤程去执行。与SwitchToThread不同,SwitchToFiber会立即切换到另一个纤程去执行(如果该线程的CPU时间还有剩余的话),而SwitchToThread要等CPU来调度另一个线程。

纤程与线程一样,也有自己的寄存器环境与函数调用栈

(2)纤程的执行上下文的构成(类似线程上下文)——大约200个字节

  ①用户自定义的值,它被初始化为传给ConvertThreadToFiber的pvParam参数的值

  ②结构化异常处理链的头

  ③纤程栈顶部和底部的内存地址(当我们将一个线程转换为一个纤程时,这时也是线程栈)

  ④某些CPU寄存器,其中包括栈指针、指令指针以及其他寄存器(注意,默认下不包含CPU的浮点状态信息)

(3)纤程运行动态示意图

第12章 纤程(Fiber)

★注意:

  在同一个线程里创建的两个纤程之间的切换是很安全的(如图中A箭头),但跨线程间的两个纤程的切换是不安全的(如图中的B、C箭头)。因为纤程本质上是由线程调度的,假设某个时刻,线程2正在调用纤程2.2,但在纤程2.2的内部调用了SwitchToFiber切换到了纤程1.2。如果CPU的下一个时间周期仍给线程2,因为内核并不知道纤程的切换,所以此时CPU仍会试图去执行纤程2.2的代码,但由于纤程的切换,会导致线程2的堆栈环境发生了变化,此时再去执行纤程2.2就可能会出现错误。

12.2 纤程的使用

(1)创建主纤程:CreateThreadToFiber(pvParam)(将已有线程转为纤程,该线程才能调用其它纤程API函数,可理解为启动线程的纤程模式

  ★注意:

    ①返回值为纤程的上下文环境,可以理解为返回一个纤程对象。

    ②默认情况下,x86 CPU的FPU信息不会被纤悉无纤程保存下来,因此在进行浮点运算时,可能破坏数据。为避免此情况,要调该新的ConvertThreadToFiberEx函数,并为dwFlags传入FIBER_FLAG_FLOAT_SWITCH标志。

(2)创建纤程(可理解为子纤程):CreateFiber

参数

描述

DWORD dwStackSize

纤程栈大小。一般传入0,表示系统自动分配

PFIBER_START_ROUTINE

pfnStartAddress

纤程函数,原型为

VOID WINAPI FiberFunc(PVOID pvParam)

PVOID pvParam

传给纤程函数的额外参数。

  ★注意:

    ①返回值为纤程的上下文环境,可以理解为返回一个纤程对象。

    ②同样,为防止发生浮点运算事故,可以调用新的API函数CreateFiberEx,并传入FIBER_FLAG_FLOAT_SWITCH标志。

(3)纤程的调度SwitchToFiber(PVOID pvFiberExcutionContext)函数,其中的参数是CreateFiber或CreateThreadToFiber返回的纤程对象(即纤程上下文环境)。注意:SwitchToFiber是让纤程得到CPU时间的唯一方法!由于我们必须显示调用SwitchtoFiber来让纤程有机会得到执行,因此纤程的调度完全在我们的掌握之中。

 ①SwitchToFiber函数的内部运行

  A.将一些CPU寄存器当前值(包括指令指针寄存器和栈指针寄存器),保存到当前正在运行的纤程的执行上下文中。

  B.从即将运行的纤程的执行上下文中,将先前保存的寄存器载入CPU寄存器。使用当线程继续执行的时候,会使用新纤程的运行环境(如栈、指令指针)

  C.将新纤程上下文与线程关联起来,让线程运行指定的纤程。

  D.将线程的指令指针设为新纤程先前保存的指令指针,这样线程(纤程)就会从上次执行的地方开始继续往下执行。

(4)纤程的删除:DeleteFiber(PVOID pvFiberExecutionContext);

  ①当纤程执行结束后,调用该函数来销毁纤程,被删除的纤程的栈将被销毁,纤程执行的上下文也会被释放。

  ②如果纤程是ConvertThreadToFiber转换得到的主纤程,当调用DeleteFiber相当于调用ExitThread直接终止线程。如果不希望终止线程,可以调用ConvertFiberToThread将主纤程转回线程,这里也会释放原来调用ConverThreadToFiber将线程转化为纤程时所占用的最后一块内存。注意,ConvertFiberToThread只转换主纤程,对其它子纤程无效

【Fiber程序】

第12章 纤程(Fiber)

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <locale.h> //////////////////////////////////////////////////////////////////////////
#define QM_ALLOC(sz) HeapAlloc(GetProcessHeap(),0,sz)
#define QM_CALLOC(sz) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz)
#define QM_SAFEFREE(p) if(NULL !=p){HeapFree(GetProcessHeap(),0,p);p=NULL;} //////////////////////////////////////////////////////////////////////////
#define BUFFER_SIZE 32768 //32*1024,即32K
#define FIBER_COUNT 3 //最大的纤程数(包含主纤程)
#define PRIMARY_FIBER 0 //主纤程的索引
#define READ_FIBER 1 //读纤程的索引
#define WRITE_FIBER 2 //写纤程的索引 #define RTN_OK 0 //RTN =Return
#define RTN_USAGE 1
#define RTN_ERROR 13 //////////////////////////////////////////////////////////////////////////
LPVOID g_lpFiber[FIBER_COUNT];
LPBYTE g_lpBuffer;
DWORD g_dwBytesRead; //分批读取的字节数,要在读和写纤程*享这个变量 //////////////////////////////////////////////////////////////////////////
typedef struct{
DWORD dwParamter; //DWORD parameter to Fiber(unnsed)
DWORD dwFiberResultCode; //GetLastError result code
HANDLE hFile; //handle to operate on
DWORD dwBytesProcessed; //number of bytes to processed
}FIBERDATASTRUCT,*PFIBERDATASTRUCT,*LPFIBERDATASTRUCT; VOID DisplayFiberInfo(void);
VOID WINAPI ReadFiberFunc(LPVOID lpParameter);
VOID WINAPI WriteFiberFunc(LPVOID lpParameter); //////////////////////////////////////////////////////////////////////////
__inline VOID GetAppPath(LPTSTR pszBuffer){
DWORD dwLen = ;
if ( == (dwLen = GetModuleFileName(NULL, pszBuffer, MAX_PATH))){
return;
} DWORD i = dwLen;
for (; i > ;i--){
if ('\\'==pszBuffer[i]){
pszBuffer[i + ] = '\0';
break;
}
}
} //////////////////////////////////////////////////////////////////////////
int _tmain(){
_tsetlocale(LC_ALL, _T("chs")); LPFIBERDATASTRUCT fs = NULL; TCHAR pSrcFile[MAX_PATH] = {};
TCHAR pDstFile[MAX_PATH] = {}; GetAppPath(pSrcFile);
GetAppPath(pDstFile);
StringCchCat(pSrcFile, MAX_PATH, TEXT("2.jpg"));
StringCchCat(pDstFile, MAX_PATH, TEXT("2_Cpy.jpg")); fs = (LPFIBERDATASTRUCT)QM_CALLOC(sizeof(FIBERDATASTRUCT)*FIBER_COUNT);
if (fs == NULL){
_tprintf(_T("HeapAlloc失败[%d]。\n"), GetLastError());
return RTN_ERROR;
} g_lpBuffer = (LPBYTE)QM_CALLOC(BUFFER_SIZE);
if (g_lpBuffer == NULL){
_tprintf(_T("HeapAlloc失败[%d]。\n"), GetLastError());
return RTN_ERROR;
} fs[READ_FIBER].hFile = CreateFile(pSrcFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (fs[READ_FIBER].hFile ==INVALID_HANDLE_VALUE){
_tprintf(_T("CreateFile失败[%d]。\n"), GetLastError());
return RTN_ERROR;
} fs[WRITE_FIBER].hFile = CreateFile(pDstFile, GENERIC_WRITE, , NULL, CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fs[WRITE_FIBER].hFile == INVALID_HANDLE_VALUE){
_tprintf(_T("CreateFile失败[%d]。\n"), GetLastError());
return RTN_ERROR;
} //主线程变为主纤程
g_lpFiber[PRIMARY_FIBER] = ConvertThreadToFiber(&fs[PRIMARY_FIBER]);
if (g_lpFiber[PRIMARY_FIBER] == NULL){
_tprintf(_T("ConvertThreadToFiber出错(%d)\n"), GetLastError());
return RTN_ERROR;
} fs[PRIMARY_FIBER].dwParamter = ;
fs[PRIMARY_FIBER].dwFiberResultCode = ;
fs[PRIMARY_FIBER].hFile = INVALID_HANDLE_VALUE; //创建读纤程
fs[READ_FIBER].dwParamter = 0x12345678;
g_lpFiber[READ_FIBER] = CreateFiber(, ReadFiberFunc, &fs[READ_FIBER]);
if (g_lpFiber[READ_FIBER] == NULL){
_tprintf(_T("CreateFiber出错(%d)\n"), GetLastError());
return RTN_ERROR;
} //创建写纤程
fs[WRITE_FIBER].dwParamter = 0x54545454;
g_lpFiber[WRITE_FIBER] = CreateFiber(, WriteFiberFunc, &fs[WRITE_FIBER]);
if (g_lpFiber[WRITE_FIBER] == NULL){
_tprintf(_T("CreateFiber出错(%d)\n"), GetLastError());
return RTN_ERROR;
} //开始执行读纤程
SwitchToFiber(g_lpFiber[READ_FIBER]); _tprintf(_T("读纤程:结果代码为%lu,%lu字节被处理\n"),
fs[READ_FIBER].dwFiberResultCode, fs[READ_FIBER].dwBytesProcessed); _tprintf(_T("写纤程:结果代码为%lu,%lu字节被处理\n"),
fs[WRITE_FIBER].dwFiberResultCode, fs[WRITE_FIBER].dwBytesProcessed); DeleteFiber(g_lpFiber[READ_FIBER]);
DeleteFiber(g_lpFiber[WRITE_FIBER]); CloseHandle(fs[READ_FIBER].hFile);
CloseHandle(fs[WRITE_FIBER].hFile); QM_SAFEFREE(g_lpBuffer);
QM_SAFEFREE(fs); //纤程变回线程
ConvertFiberToThread(); _tsystem(_T("PAUSE"));
return RTN_OK;
} VOID WINAPI ReadFiberFunc(LPVOID lpParameter){
LPFIBERDATASTRUCT pfds = (LPFIBERDATASTRUCT)lpParameter; if (pfds == NULL){
_tprintf(_T("传递的纤程数据为NULL,退出当前线程\n"));
return;
} pfds->dwBytesProcessed = ;
while (){
DisplayFiberInfo();
if (!ReadFile(pfds->hFile,g_lpBuffer,BUFFER_SIZE,&g_dwBytesRead,NULL)){
break;
}
if (g_dwBytesRead ==){
break;
} pfds->dwBytesProcessed += g_dwBytesRead;
SwitchToFiber(g_lpFiber[WRITE_FIBER]);
} //while pfds->dwFiberResultCode = GetLastError();
SwitchToFiber(g_lpFiber[PRIMARY_FIBER]);
} VOID WINAPI WriteFiberFunc(LPVOID lpParameter){
LPFIBERDATASTRUCT pfds = (LPFIBERDATASTRUCT)lpParameter; DWORD dwBytesWritten;
if (pfds == NULL){
_tprintf(_T("传递的纤程数据为NULL,退出当前线程.\n"));
return;
} pfds->dwBytesProcessed = ;
pfds->dwFiberResultCode = ERROR_SUCCESS; while (){
DisplayFiberInfo();
if (!WriteFile(pfds->hFile,g_lpBuffer,g_dwBytesRead,&dwBytesWritten,NULL)){
break;
} pfds->dwBytesProcessed += dwBytesWritten;
SwitchToFiber(g_lpFiber[READ_FIBER]); //接着读取数据
}//while pfds->dwFiberResultCode = GetLastError();
SwitchToFiber(g_lpFiber[PRIMARY_FIBER]);
} VOID DisplayFiberInfo(void){
LPFIBERDATASTRUCT pfds = (LPFIBERDATASTRUCT)GetFiberData();
LPVOID lpCurrentFiber = GetCurrentFiber(); if (lpCurrentFiber == g_lpFiber[READ_FIBER]){
_tprintf(_T("读纤程进入!"));
} else{
if (lpCurrentFiber == g_lpFiber[WRITE_FIBER]){
_tprintf(_T("写纤程进入!"));
} else{
if (lpCurrentFiber == g_lpFiber[PRIMARY_FIBER]){
_tprintf(_T("主纤程进入!"));
} else{
_tprintf(_T("未知纤程进入!"));
}
}
} _tprintf(_T("dwParameter为0x%1X\n"), pfds->dwParamter);
}

12.3 纤程的本地存储(Fiber Local Storage,FLS)

(1)使用FLS的步骤(类似于TLS):

  ①调用FlsAlloc分配FLS索引

  ②调用FlsSetValue将Fiber的值写入该索引FLS

  ③调用FlsGetValue取得Fiber存储的FLS值

  ④调用FlsFree释放FLS索引

(2)FlsAlloc中可以指定一个回调函数:VOID WINAPI FlsCallback(PVOID lpFlsData);

  【说明】回调函数会在纤程被销毁、调度纤程的线程退出或FlsFree时被调用,这主要便纤程有机会删除自己在FLS中存储的值。

(3)获取当前纤程对象(上下文环境):PVOID GetCurrentFiber();

(4)获得创建纤程时的pvParam数据:GetFiberData

(5)判断是否正在某个纤程中运行:IsThreadFiber()

【FLS程序】演示如何使用纤程本地存储

第12章 纤程(Fiber)

#include <tchar.h>
#include <windows.h>
#include <strsafe.h>
#include <locale.h> //////////////////////////////////////////////////////////////////////////
#define QM_ALLOC(sz) HeapAlloc(GetProcessHeap(),0,sz)
#define QM_CALLOC(sz) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz)
#define QM_SAFEFREE(p) if (NULL != p){HeapFree(GetProcessHeap(),0,p);p=NULL;} //////////////////////////////////////////////////////////////////////////
#define FIBER_COUNT 3
#define PRIMARY_FIBER 0 //主纤程的数组索引 LPVOID g_lpFiber[FIBER_COUNT] = {};
DWORD g_dwFlsIndex = ; //////////////////////////////////////////////////////////////////////////
VOID _stdcall FiberFunc(LPVOID lpParameter); int _tmain(){
_tsetlocale(LC_ALL, _T("chs")); //主线程变为纤程
g_lpFiber[PRIMARY_FIBER] = ConvertThreadToFiber(NULL);
if (g_lpFiber[PRIMARY_FIBER]==NULL){
_tprintf(_T("ConvertThreadToFiber出错(%d)\n"), GetLastError());
return -;
} g_dwFlsIndex = FlsAlloc(NULL);
if (FLS_OUT_OF_INDEXES == g_dwFlsIndex){
_tprintf(_T("FlsAlloc出错(%d)"), GetLastError());
return -;
} //创建2个子纤程
for (int i = ; i< FIBER_COUNT;i++){
g_lpFiber[i] = CreateFiber(, FiberFunc, NULL);
if (g_lpFiber[i]==NULL){
_tprintf(_T("CreateFiber出错(%d)\n"), GetLastError());
return -;
}
} //轮流调度
for (int i = ; i < FIBER_COUNT;i++){
SwitchToFiber(g_lpFiber[i]);
} //删除纤程
for (int i = ; i < FIBER_COUNT;i++){
DeleteFiber(g_lpFiber[i]);
} FlsFree(g_dwFlsIndex); //纤程变回线程
ConvertFiberToThread(); _tsystem(_T("PAUSE"));
return ;
} VOID _stdcall FiberFunc(LPVOID lpParameter){
FlsSetValue(g_dwFlsIndex, GetCurrentFiber());
_tprintf(_T("纤程[0x%x]保存的Fls值(%u)\n"),
GetCurrentFiber(),FlsGetValue(g_dwFlsIndex));
SwitchToFiber(g_lpFiber[PRIMARY_FIBER]);
}

【Counter示例程序】使用纤程进行计数

第12章 纤程(Fiber)      第12章 纤程(Fiber)

计算中                                     窗口拖动中(重算纤程停止)

/*************************************************************************
Module: Counter.cpp
Notices:Copyright(c) 2008 Jeffrey Ritchter & Christophe Nasarre
*************************************************************************/
#include "../../CommonFiles/CmnHdr.h"
#include <tchar.h>
#include <strsafe.h>
#include "resource.h" //////////////////////////////////////////////////////////////////////////
//后台处理过程(Background Processing)可能的状态
typedef enum{
BPS_STARTOVER,//从新开始后台处理过程
BPS_CONTINUE, //继续后台处理过程
BPS_DONE //后台处理结束
}BKGNDPROCSTATE; typedef struct{
PVOID pFiberUI; //用户纤程对象(上下文)
HWND hwnd; //UI窗口句柄
BKGNDPROCSTATE bps; //后台处理过程的状态
}FIBERINFO,*PFIBERINFO; //////////////////////////////////////////////////////////////////////////
//应用程序运行状态,该变量可以由UI纤程直接访问,后台处理过程可间接地访问
FIBERINFO g_FiberInfo; //纤程局部存储索引值(FLS槽)
DWORD g_dwSlot = ; //////////////////////////////////////////////////////////////////////////
//FlsAlloc中指定的回调函数
VOID WINAPI LogMessage(PVOID pFlsValue){
TCHAR szMsg[MAX_PATH]; //检查线程是否在纤程中,因为该回调函数可能在纤程之外被调用
//只有在纤程中运行,才能使用FLS槽里的值
if (IsThreadAFiber()){
PVOID pFiber= GetCurrentFiber();
PCTSTR pszFlsValue = (PCTSTR)FlsGetValue(g_dwSlot);
StringCchPrintf(szMsg, _countof(szMsg), TEXT("[0x%x - %s] %s\n"),
pFiber,
(pszFlsValue == NULL)? TEXT("'Null 值'"):(PCTSTR)pszFlsValue,
(pFlsValue == NULL) ? TEXT("'Null 值'") : (PCTSTR)pFlsValue);
} else{
StringCchCopy(szMsg, _countof(szMsg), TEXT("不再是一个纤程...\n"));
} OutputDebugString(szMsg);
} //////////////////////////////////////////////////////////////////////////
void WINAPI FiberFunc(LPVOID lpParameter){
PFIBERINFO pFiberInfo = (PFIBERINFO)lpParameter; FlsSetValue(g_dwSlot, TEXT("Computation"));
LogMessage(TEXT("进入 计算中...")); //显示当前正在运行的纤程
SetDlgItemText(pFiberInfo->hwnd, IDC_FIBER, TEXT("后台重算纤程")); //获取当前编辑框中的计数器值
int nCount = GetDlgItemInt(pFiberInfo->hwnd, IDC_COUNT, NULL, FALSE); //从0到计数到nCount,并更新Answer的内容
for (int x = ; x <= nCount;x++){
//检查线程的消息队列是否有新的消息(在同一个线程中运行的所有
//纤程共享该线程的消息队列)
if (HIWORD(GetQueueStatus(QS_ALLEVENTS))!=){
//UI纤程事件到达,先去暂停后台处理 ,转去处理UI事件
SwitchToFiber(pFiberInfo->pFiberUI); //UI事件处理完毕,后台继续计算
SetDlgItemText(pFiberInfo->hwnd, IDC_FIBER, TEXT("后台重算纤程"));
} //更新Answer
SetDlgItemInt(pFiberInfo->hwnd, IDC_ANSWER, x, FALSE); //为了夸大效果,睡眠一会儿
Sleep();
} //计算结束
pFiberInfo->bps = BPS_DONE; //重新调度UI线程。当线程正在运行并且没有UI事件可处理时,线程将进入睡眠状态
//(因为UI线程调用了WaitMessage)
SwitchToFiber(pFiberInfo->pFiberUI);
} //////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){
SetDlgItemInt(hwnd, IDC_COUNT, , FALSE);
return TRUE;
} void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtrl, UINT codeNotify){
switch (id)
{
case IDCANCEL:
PostQuitMessage();
break; case IDC_COUNT:
if (codeNotify == EN_CHANGE){
//当用户改变了计数值 ,重新开始后台处理过程
g_FiberInfo.bps = BPS_STARTOVER;
}
break;
}
}
//////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
switch (uMsg)
{
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
}
return FALSE;
} //////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nShowCmd)
{
//后台处理的纤程对象
PVOID pFiberCounter = NULL; //主线程转为主纤程
g_FiberInfo.pFiberUI = ConvertThreadToFiber(NULL); g_dwSlot = FlsAlloc(LogMessage); //Fls索引
FlsSetValue(g_dwSlot, TEXT("UI Fiber")); //创建应用程序UI窗口
g_FiberInfo.hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_COUNTER), NULL, Dlg_Proc); //更新显示当前正在运行的纤程
SetDlgItemText(g_FiberInfo.hwnd, IDC_FIBER, TEXT("用户界面纤程")); //初始化时,当前没有后台处理任务
g_FiberInfo.bps = BPS_DONE; //消息循环
BOOL fQuit = FALSE;
while (!fQuit){
//UI消息比后台处理过程有更高的优先级
MSG msg;
if (PeekMessage(&msg,NULL,,,PM_REMOVE)){
if (!IsDialogMessage(g_FiberInfo.hwnd,&msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
fQuit = (msg.message == WM_QUIT); if (fQuit){
//释放FLS槽
FlsFree(g_dwSlot); //停止后台处理过程
if (pFiberCounter !=NULL){
DeleteFiber(pFiberCounter);
pFiberCounter = NULL;
}
//退出纤程模式并返回单线程模式
ConvertFiberToThread();
g_FiberInfo.pFiberUI = NULL;
}
} else{ //没有UI消息时,检查后台过程的状态
switch (g_FiberInfo.bps)
{
case BPS_DONE:
//没有后台过程则等待UI事件
WaitMessage();
break; case BPS_STARTOVER:
//用户改变了计数值
//先取消当前的后台处理程序,然后重新开始后台处理
if (pFiberCounter !=NULL){
DeleteFiber(pFiberCounter);
pFiberCounter = NULL;
}
//将主线程转化为主纤程
if (g_FiberInfo.pFiberUI ==NULL){
g_FiberInfo.pFiberUI = ConvertThreadToFiber(NULL);
} //LogMessage
LogMessage(TEXT("转换UI线程为纤程中...")); //创建一个新的重计算纤程
pFiberCounter = CreateFiber(, FiberFunc, &g_FiberInfo); //后台处理进程开始
g_FiberInfo.bps = BPS_CONTINUE;
//注意,这里没有break,贯穿执行下去。
case BPS_CONTINUE:
//允许后台处理开始
SwitchToFiber(pFiberCounter); //后台处理被暂停(可能因为UI消息或被计算完成被自动暂停)
//显示哪个纤程正在被执行中
SetDlgItemText(g_FiberInfo.hwnd, IDC_FIBER, TEXT("用户界面纤程")); if (g_FiberInfo.bps == BPS_DONE){
//完成后台处理,删除纤程以便下次重新执行计算
DeleteFiber(pFiberCounter);
pFiberCounter = NULL; //退出纤程模式并重回单线程模式
ConvertFiberToThread();
g_FiberInfo.pFiberUI = NULL;
}
break;
} //Switch,后台处理状态 } //没有UI消息
} //While,窗口仍然存在 DestroyWindow(g_FiberInfo.hwnd);
return ; //结束程序
}

//resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 12_Counter.rc 使用
//
#define IDD_COUNTER 101
#define IDC_COUNT 1001
#define IDC_ANSWER 1002
#define IDC_FIBER 1003 // Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1004
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

//Counter.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h" #define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h" /////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS /////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
// TEXTINCLUDE
BEGIN
"resource.h\0"
END TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END #endif // APSTUDIO_INVOKED /////////////////////////////////////////////////////////////////////////////
//
// Dialog
// IDD_COUNTER DIALOGEX , , ,
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "计数器"
FONT , "宋体", , , 0x86
BEGIN
LTEXT "计数到:",IDC_STATIC,,,,
EDITTEXT IDC_COUNT,,,,,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "当前值:",IDC_STATIC,,,,
LTEXT "",IDC_ANSWER,,,,
LTEXT "当前正在运行的纤程:",IDC_STATIC,,,,
LTEXT "Fiber",IDC_FIBER,,,,
END /////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
// #ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_COUNTER, DIALOG
BEGIN
LEFTMARGIN,
RIGHTMARGIN,
TOPMARGIN,
BOTTOMMARGIN,
END
END
#endif // APSTUDIO_INVOKED #endif // 中文(简体,中国) resources
///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
// /////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

第12章 纤程(Fiber)的更多相关文章

  1. Windows核心编程:第12章 纤程

    Github https://github.com/gongluck/Windows-Core-Program.git //第12章 纤程.cpp: 定义应用程序的入口点. // #include & ...

  2. Windows核心编程 第十二章 纤程

    第1 2章 纤 程 M i c r o s o f t公司给Wi n d o w s添加了一种纤程,以便能够非常容易地将现有的 U N I X服务器应用程序移植到Wi n d o w s中.U N I ...

  3. 基于纤程&lpar;Fiber&rpar;实现C&plus;&plus;异步编程库(一):原理及示例

    纤程(Fiber)和协程(coroutine)是差不多的概念,也叫做用户级线程或者轻线程之类的.Windows系统提供了一组API用户创建和使用纤程,本文中的库就是基于这组API实现的,所以无法跨平台 ...

  4. 继续了解Java的纤程库 – Quasar

    前一篇文章Java中的纤程库 – Quasar中我做了简单的介绍,现在进一步介绍这个纤程库. Quasar还没有得到广泛的应用,搜寻整个github也就pinterest/quasar-thrift这 ...

  5. nodejs中的fiber(纤程)库详解

    fiber/纤程 在操作系统中,除了进程和线程外,还有一种较少应用的纤程(fiber,也叫协程).纤程常常拿来跟线程做对比,对于操作系统而言,它们都是较轻量级的运行态.通常认为纤程比线程更为轻量,开销 ...

  6. 协程,纤程(Fiber),或者绿色线程(GreenThread)

    纤程(Fiber),或者绿色线程(GreenThread) 面试官:你知道协程吗? 你:订机票的那个吗,我常用. 面试官:行,你先回去吧,到时候电话联系 ........ 很尴尬,但是事实是,很大一部 ...

  7. 纤程(FIBER)

    Indy 10 还包含对纤程的支持.纤程是什么?简单来说,它也是 一个“线程”,但是它是由代码控制的,而不是由操作系统控制的.实际上,可以认为线程 是一个高级纤程.纤程和 Unix 用户线程(Unix ...

  8. 第 12 章 python并发编程之协程

    一.引子 主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只用一个)情况下实现并发,并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作 ...

  9. Java 中的纤程库 – Quasar

    来源:鸟窝, colobu.com/2016/07/14/Java-Fiber-Quasar/ 如有好文章投稿,请点击 → 这里了解详情 最近遇到的一个问题大概是微服务架构中经常会遇到的一个问题: 服 ...

随机推荐

  1. zk 隐藏网页文件后缀

    前台(test.zul): <a label="隐藏地址" href="/Bandbox/test.html"/> web.xml添加 <se ...

  2. 【Linux常识篇&lpar;3&rpar;】文件及文件夹的ctime atime mtime的含义详解

    首先可以使用stat 命令来查询文件的inode信息,其中包括ctime atime mtime [root@localhost ~]# stat sort2.txt File: 'sort2.txt ...

  3. hdu1198 Farm Irrigation 并查集

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1198 简单并查集 分别合并竖直方向和水平方向即可 代码: #include<iostream&g ...

  4. javaSE&lowbar;06Java中的数组(array)

    1.什么是数组? 顾名思义,即为数据的组合或集合,数组就是用来表示一组数据的. 比如没有数组之前,我们要存储多个姓名的信息 String name1; String name2; String nam ...

  5. C&num; 模拟浏览器请求

    public string getHtml(string Url, string type = "UTF-8")        {            try           ...

  6. 2018年Web前端自学路线

    本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. Web前端入门的自学路线 新手入门前端,需要学习的基础内容有很多,如下. ...

  7. 采购申请 POCIRM-001:ORA-01403&colon; 未找到任何数据

    今天同事让帮忙看一个问题,在销售模块提交销售订单生成采购订单的请求时报错 查看请求日志 +------------------------------------------------------- ...

  8. 使用padding后内容超出父级元素

    解决方法:

  9. 最小化spring XML配置,Spring提供了4种自动装配策略。

    1.ByName自动装配:匹配属性的名字 在配置文件中的写法: <bean name="course" class="course类的全包名">&l ...

  10. docker&plus;springboot&plus;elasticsearch&plus;kibana&plus;elasticsearch-head整合(详细说明 &comma;看这一篇就够了)

    一开始是没有打算写这一篇博客的,但是看见好多朋友问关于elasticsearch的坑,决定还是写一份详细的安装说明与简单的测试demo,只要大家跟着我的步骤一步步来,100%是可以测试成功的. 一.  ...