Drecik學習經驗分享
轉載請註明出處:http://blog.csdn.net/drecik__/article/details/8202023
Windows提供纖程是爲了幫助各個公司更快地、正確地將它們的代碼從UNIX移植到Windows中。
但我們要記住,自己在Windows上設計程序時,應該避免使用纖程,而使用Windows提供的線程機制。
首先要了解的是,纖程是在用戶模式下實現的,內核對纖程一無所知,內核會根據我們定義的算法來對纖程進行調度。
一個線程可以包含一個或多個纖程。對內核而言它會對線程進行搶佔式調度來讓線程執行代碼,但是,線程一次只能執行一個纖程代碼(由我們決定哪個纖程)。
使用纖程的步驟:
通過函數ConvertThreadToFiber將一個已有的線程轉化爲一個纖程:
LPVOID // 返回纖程執行上下文的地址; ConvertThreadToFiber( LPVOID lpParameter );
該函數會創建一個纖程的執行上下文,有下面元素構成:
默認情況下CPU浮點狀態信息不屬於CPU寄存器一部分,不會每個纖程都維護一份,如果纖程需要執行浮點操作,則需要使用函數ConvertThreadToFiberEx來轉換:
- 一個用戶自定義的值,即傳入的lpParameter參數
- 結構化異常處理鏈的頭
- 纖程棧的頂部和底部的內存地址
- 某些CPU寄存器,其中包括棧指針,指令指針以及其他寄存器
LPVOID ConvertThreadToFiberEx( LPVOID lpParameter, DWORD dwFlags // 傳入FIBER_FLAG_FLOAT_SWITCH標誌; );
除非打算創建更多的纖程,並讓它們在同一個線程中運行,否則沒有理由將一個線程轉換爲纖程,創建另一個纖程,當前線程使用CreateFiber或CreateFiberEx:
LPVOID // 返回纖程執行上下文的地址; CreateFiber( SIZE_T dwStackSize, // 棧大小,通常爲0; LPFIBER_START_ROUTINE lpStartAddress, // 指定纖程函數的地址; LPVOID lpParameter // 用戶自定義值,會保存到纖程執行上下文; ); LPVOID CreateFiberEx( SIZE_T dwStackCommitSize, // 指定一開始要調撥的物理存儲頁; SIZE_T dwStackReserveSize, // 預定指定數量的虛擬內存; DWORD dwFlags, // 可以指定需要進行浮點操作,傳入FIBER_FLAG_FLOAT_SWITCH標誌; LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ); // 纖程函數的函數原型; // 該函數不應該返回,如果返回,該線程以及它創建的所有纖程都會立即被銷燬; typedef VOID (WINAPI *PFIBER_START_ROUTINE)( LPVOID lpFiberParameter // 傳入用戶自定義的值; );
CreateFiber(Ex)與ConvertTreadToFiber(Ex)不同之處在於,它創建的纖程不會立即執行,因爲當前運行的纖程還在執行,在同一時刻只能執行一個纖程,可以使用SwitchToFiber來讓新的纖程執行:
VOID SwitchToFiber( LPVOID lpFiber // 纖程執行上下文地址; );
在內部該函數會將正在執行的纖程CPU寄存器保存起來在執行上下文中,然後將要執行纖程的CPU寄存器載入到CPU中,並將新的纖程與線程關聯,讓線程運行指定的纖程,最後就是載入指令指針,讓纖程從上次運行的地方開始執行。
最後可以調用DeleteFiber啦銷燬纖程:
VOID DeleteFiber( LPVOID lpFiber // 纖程執行上下文地址; );
函數會刪除該參數標識的纖程,並釋放線程的棧並銷燬纖程的執行上下文,如果該纖程與線程正在關聯,則會在內部調用ExitThread,從而使線程以及爲它創建的纖程都結束。
DeleteFiber通常爲一個纖程調用,以刪除另一個纖程,與線程不同,線程是最好不要終止另外一個線程。
當所有纖程都被刪除,可以調用ConvertFiberToThread(Ex)來解除線程的纖程狀態,同時釋放最後一塊內存塊。
如果想知道當先的線程相關聯的纖程地址,可以調用GetCurrentFiber,也可以調用GetFiberData返回用戶自定義的值。