12.1 纤程对象的介绍

(1)纤程与线程的比较

比较

线程(Thread)

纤程(Fiber)

实现方式

是个内核对象

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

调度方式

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

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

备注

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

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

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

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

  ②结构化异常处理链的头

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

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

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

★注意:

  在同一个线程里创建的两个纤程之间的切换是很安全的(如图中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程序】

#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程序】演示如何使用纤程本地存储

#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示例程序】使用纤程进行计数

      

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

/*************************************************************************
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. 基于纤程(Fiber)实现C++异步编程库(一):原理及示例

    纤程(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. webpack常用的插件安装命令

    webpack常用的插件安装命令:1:npm install html-webpack-plugin --save-dev //自动快速的帮我们生成HTML.2:npm install css-loa ...

  2. RHEL7进程管理

    进程概念 名称 说明 程序 一组指令的集合 进程 程序的执行就是进程也可以把进程看成一个独立的程序在内存中有其对应的代码空间和数据空间,一个进程所拥有的数据和代码只属于自己进程是资源分配的基本单位,也 ...

  3. 通过FTP连接Azure上的网站

    下载发布文件 使用记事本(或其他文本工具)打开 找到ftp连接地址以及用户名.密码 使用ftp工具进行连接 输入相应参数,连接即可

  4. ALV要特别小心的一些地方

    1.在ALV报表里面如果你做了一个字段可编辑而且这个字段是带有小数的数量或者金额,这时候当你输入一个数字保存或者去操作的时候发现他的值会变掉,这个要在设置列属性的时候给他对应的参考表和字段L_FIEL ...

  5. 转:NLog之:文件类型目标(File target)

    转:http://www.cnblogs.com/RitchieChen/archive/2012/07/16/2594308.html 英文原文[http://nlog-project.org/wi ...

  6. Android中方便好用的倒计时类

       一.使用api提供的类进行操作 Android提供了CountDownTimer来让我们进行倒计时,可以让我们很方便的进行倒计时的操作.使用方式也很简单,下面直接贴代码就好了: package ...

  7. 全球最低功耗蓝牙单芯片DA14580的软件体系 -层次架构和BLE消息事件处理过程

    在作者之前发表的<全球最低功耗蓝牙单芯片DA14580的系统架构和应用开发框架分析>.<全球最低功耗蓝牙单芯片DA14580的硬件架构和低功耗>.<全球最低功耗蓝牙单芯片 ...

  8. 自己使用 1.C语言历史以及特点。

    1. C语言的发展及特点? C在1969--1973年间与Unix操作系统同时诞生:最富创造性的时期是1972年.另一次大的变化发生在1977到1979年间,当Unix系统的可移植性得到证明时.在后一 ...

  9. .NET 创建Windows服务,及服务的安装卸载

    .NET服务创建过程 http://jingyan.baidu.com/article/fa4125acb71a8628ac709226.html 相关命令(要以管理员身份打开cmd) 安装服务 -& ...

  10. 【mysql】关于checkpoint机制

    一.简介 思考一下这个场景:如果重做日志可以无限地增大,同时缓冲池也足够大,那么是不需要将缓冲池中页的新版本刷新回磁盘.因为当发生宕机时,完全可以通过重做日志来恢复整个数据库系统中的数据到宕机发生的时 ...