在Windows2000/XP中,纖程(fiber)相當於使用者層級的線程或輕進程.纖程由Win32庫函數支援,對核心是不可見的.纖程可以通過SwitchToFiber顯示至另一合作纖程,以實現合作纖程之間的協同.
纖程包含獨立的目態棧,寄存器狀態的控制資訊.目態控制的纖程轉接要求較高的編程經驗.由於纖程屬於目態對象,一個纖程被封鎖意味著所線上程被封鎖.應用程式可以通過ConvertThreadToFiber將線程轉換為纖程.與線程對比,纖程具有切換速度快的特點.
Microsoft公司給Windows添加了一種纖程,以便能夠非常容易地將現有的UNIX伺服器應用程式移植到Windows中。UNIX伺服器應用程式屬於單線程應用程式(由Windows定義),但是它能夠為多個客戶程式提供服務。換句話說, UNIX應用程式的開發人員已經建立了他們自己的線程結構庫,他們能夠使用這種線程結構庫來模擬純線程。該線程包能夠建立多個堆棧,儲存某些C P U寄存器,並且在它們之間進行切換,以便為客戶機請求提供服務。
顯然,若要取得最佳的效能,這些UNIX應用程式必須重新設計,模擬的線程庫應該用Windows提供的純線程來替代。然而,這種重新設計需要花費數月甚至更長的時間才能完成,因此許多公司首先將它們現有的UNIX代碼移植到Windows中,這樣就能夠將某些應用軟體推向Windows市場。
使用纖程
線程是在Windows核心中實現的,纖程是在使用者模式下實現的,核心對纖程一無所知,核心會根據我們定義的演算法來對纖程進行調度。
一個線程可以包含一個或多個纖程。
轉化線程為纖程
使用纖程的第一個步驟是將已有的線程轉換為一個纖程。ConvertThreadToFiber這個函數會為纖程的上下文分配記憶體,這個內容相關的構成是:
# 一個使用者自訂的值
# 結構化異常處理鏈的頭
# 纖程棧的頂部和底部的記憶體位址
# 某些CPU寄存器,其中包括棧指標、指令指標以及其他寄存器
當我們分配了纖程執行內容並對其進行初始化之後,還必須將執行內容的地址與線程關聯起來。這樣我們就將線程轉換成了一個纖程,該纖程在這個線程中執行。
其實,除非我們打算建立更多的纖程,並讓它們在同一個線程中運行,否則沒有理由將一個線程轉換為纖程。
CreateFiber:建立一個纖程
SwitchToFiber:調用一個纖程(同一個線程中,同一時刻只能執行一個纖程)
DeleteFiber:通常為一個纖程調用,來刪除另一個纖程
GetCurrentFiber:得到當前正在啟動並執行纖程
**************************************/<br />/* 預定義 */<br />#define _WIN32_WINNT 0x0501<br />/* 標頭檔 */<br />#include <windows.h><br />#include <stdio.h><br />/* 函式宣告 */<br />VOID WINAPI ReadFiberFunc( LPVOID lpParameter );<br />VOID WINAPI WriteFiberFunc( LPVOID lpParameter );<br />/* 結構定義 */<br />// 用於向纖程傳遞參數<br />// 本執行個體是使用讀、寫檔案來示範纖程的調度<br />// 使用者可根據實際情況自行定義<br />typedef struct _FIBERDATASTRUCT<br />{<br />DWORD dwParameter;// 預留給向纖程傳遞待定參數<br />DWORD dwFiberResultCode;// GetLastError() 值<br />HANDLE hFile;// 纖程所操作檔案的控制代碼<br />DWORD dwBytesProcessed;// 已經處理了的位元組<br />}FIBERDATASTRUCT, *LPFIBERDATASTRUCT;<br />/* 常量定義 */<br />#define RTN_OK 0// 傳回值 成功<br />#define RTN_USAGE 1// 傳回值 參數不正確<br />#define RTN_ERROR 2// 傳回值 錯誤<br />#define BUFFER_SIZE 32768// 緩衝區大小<br />#define FIBER_COUNT 3// 主纖程、讀纖程、寫纖程,共三個<br />#define PRIMARY_FIBER 0// 主纖程<br />#define READ_FIBER 1// 讀纖程<br />#define WRITE_FIBER 2// 寫纖程</p><p>LPVOID g_lpFiber[FIBER_COUNT];// 纖程地址的數組<br />LPBYTE g_lpBuffer;// 緩衝區<br />DWORD g_dwBytesRead;// 已讀的位元組</p><p>int main( int argc, char *argv[] )<br />{<br />LPFIBERDATASTRUCT fs;<br />// 用法說明<br />if (argc != 3)<br />{<br />printf("Usage: %s <SourceFile> <DestinationFile>\n", argv[0]);<br />return RTN_USAGE;<br />}<br />// 分配FIBERDATASTRUCT空間,FIBER_COUNT個<br />fs = (LPFIBERDATASTRUCT)HeapAlloc(<br />GetProcessHeap(), 0,<br />sizeof(FIBERDATASTRUCT) * FIBER_COUNT);<br />if (fs == NULL)<br />{<br />printf("HeapAlloc error! (rc%=lu)\n", GetLastError());<br />return RTN_ERROR;<br />}<br />//分配讀、寫緩衝區<br />g_lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, BUFFER_SIZE);<br />if (g_lpBuffer == NULL)<br />{<br />printf("HeapAlloc error! (rc=%lu)\n", GetLastError());<br />return RTN_ERROR;<br />}<br />// 開啟源檔案,將控制代碼賦值給fs結構的hFile成員,使纖程可以使用該控制代碼<br />fs[READ_FIBER].hFile = CreateFile(<br />argv[1], GENERIC_READ,<br />FILE_SHARE_READ, NULL, OPEN_EXISTING,<br />FILE_FLAG_SEQUENTIAL_SCAN, NULL<br />);<br />if (fs[READ_FIBER].hFile == INVALID_HANDLE_VALUE)<br />{<br />printf("CreateFile error! (rc=%lu)\n", GetLastError());<br />return RTN_ERROR;<br />}<br />// 開啟目標檔案<br />fs[WRITE_FIBER].hFile = CreateFile(<br />argv[2], GENERIC_WRITE,<br />0, NULL, CREATE_NEW,<br />FILE_FLAG_SEQUENTIAL_SCAN, NULL<br />);<br />if (fs[WRITE_FIBER].hFile == INVALID_HANDLE_VALUE)<br />{<br />printf("CreateFile error! (rc=%lu)\n", GetLastError());<br />return RTN_ERROR;<br />}</p><p>// 將主線程切換為纖程,為主纖程,只有轉換為纖程後才可以切換至其他纖程<br />g_lpFiber[PRIMARY_FIBER]=ConvertThreadToFiber(&fs[PRIMARY_FIBER]);<br />if (g_lpFiber[PRIMARY_FIBER] == NULL)<br />{<br />printf("ConvertThreadToFiber failed! rc=%lu\n", GetLastError());<br />return RTN_ERROR;<br />}<br />// 主纖程資料<br />fs[PRIMARY_FIBER].dwParameter = 0;<br />fs[PRIMARY_FIBER].dwFiberResultCode = 0;<br />fs[PRIMARY_FIBER].hFile = INVALID_HANDLE_VALUE;<br />// 建立讀纖程<br />g_lpFiber[READ_FIBER]=CreateFiber(0,ReadFiberFunc,&fs[READ_FIBER]);<br />if (g_lpFiber[READ_FIBER] == NULL)<br />{<br />printf("CreateFiber error! (rc=%lu)\n", GetLastError());<br />return RTN_ERROR;<br />}<br />// 將纖程指標作為參數傳給纖程,沒有實際意義,為了顯示相關資訊時區別各纖程<br />fs[READ_FIBER].dwParameter = (DWORD)g_lpFiber[READ_FIBER];<br />// 建立寫纖程<br />g_lpFiber[WRITE_FIBER]=CreateFiber(0,WriteFiberFunc,&fs[WRITE_FIBER]);</p><p>if (g_lpFiber[WRITE_FIBER] == NULL)<br />{<br />printf("CreateFiber error! (rc=%lu)\n", GetLastError());<br />return RTN_ERROR;<br />}<br />fs[WRITE_FIBER].dwParameter = (DWORD)g_lpFiber[WRITE_FIBER];<br />// 切換到讀程式執行<br />SwitchToFiber(g_lpFiber[READ_FIBER]);</p><p>// 由讀纖程獲寫纖程切換回主纖程<br />// 顯示相關資訊<br />printf("ReadFiber result == %lu Bytes Processed == %lu\n",<br />fs[READ_FIBER].dwFiberResultCode, fs[READ_FIBER].dwBytesProcessed);</p><p>printf("WriteFiber result == %lu Bytes Processed == %lu\n",<br />fs[WRITE_FIBER].dwFiberResultCode, fs[WRITE_FIBER].dwBytesProcessed);<br />// 刪除讀寫纖程<br />DeleteFiber(g_lpFiber[READ_FIBER]);<br />DeleteFiber(g_lpFiber[WRITE_FIBER]);<br />// 關閉檔案控制代碼、釋放記憶體、返回<br />CloseHandle(fs[READ_FIBER].hFile);<br />CloseHandle(fs[WRITE_FIBER].hFile);<br />HeapFree(GetProcessHeap(), 0, g_lpBuffer);<br />HeapFree(GetProcessHeap(), 0, fs);<br />return RTN_OK;<br />}</p><p>VOID WINAPI ReadFiberFunc( LPVOID lpParameter )<br />{<br />LPFIBERDATASTRUCT fds = (LPFIBERDATASTRUCT)lpParameter;</p><p>// 判斷參數<br />if (fds == NULL)<br />{<br />printf("Passed NULL fiber data. Exiting current thread.\n");<br />return;<br />}<br />// 顯示纖程資訊<br />printf("Read Fiber (dwParameter == 0x%lx)\n", fds->dwParameter);<br />// 初始化處理的位元組數為0<br />fds->dwBytesProcessed = 0;<br />// 迴圈讀<br />while (1)<br />{<br />if (!ReadFile(fds->hFile, g_lpBuffer, BUFFER_SIZE,<br />&g_dwBytesRead, NULL))<br />{<br />break;<br />}<br />// 判斷檔案是否已經讀完<br />if (g_dwBytesRead == 0) break;</p><p>// 已經處理的位元組,累加<br />fds->dwBytesProcessed += g_dwBytesRead;</p><p>// 讀一次後切換到寫纖程,將讀出的資料寫入到目標檔案<br />printf("Switch To Write");<br />SwitchToFiber(g_lpFiber[WRITE_FIBER]);<br />}<br />// 讀操作完成,準備交出執行,返回到主纖程中<br />fds->dwFiberResultCode = GetLastError();<br />SwitchToFiber(g_lpFiber[PRIMARY_FIBER]);<br />}</p><p>VOID WINAPI WriteFiberFunc( LPVOID lpParameter )<br />{<br />LPFIBERDATASTRUCT fds = (LPFIBERDATASTRUCT)lpParameter;<br />DWORD dwBytesWritten;</p><p>// 判斷參數<br />if (fds == NULL)<br />{<br />printf("Passed NULL fiber data. Exiting current thread.\n");<br />return;<br />}<br />// 顯示纖程資訊<br />printf("Write Fiber (dwParameter == 0x%lx)\n", fds->dwParameter);<br />// 初始化,注意和讀纖程的不同<br />fds->dwBytesProcessed = 0;<br />fds->dwFiberResultCode = ERROR_SUCCESS;</p><p>while (1)<br />{<br />// 寫入資料<br />if (!WriteFile(fds->hFile, g_lpBuffer, g_dwBytesRead,<br />&dwBytesWritten, NULL))<br />{<br />// 如果發生錯誤,退出迴圈<br />break;<br />}<br />fds->dwBytesProcessed += dwBytesWritten;</p><p>// 寫入完成,切換到讀纖程<br />printf("Switch To Write");<br />SwitchToFiber(g_lpFiber[READ_FIBER]);<br />}<br />// 出錯,切換到主纖程<br />// 如果寫操作不出錯,是不可能由寫纖程切換回主纖程的<br />fds->dwFiberResultCode = GetLastError();<br />SwitchToFiber(g_lpFiber[PRIMARY_FIBER]);<br />}