《Win32 多線程程序設計》讀書筆記

 一、多線程的誕生

人們吃飯的時候總是這樣的:一邊吃一邊喝一邊呼吸。如果我是創建人類的大自然,我肯定會選擇搶先式多任務。

    如果蓋房,這需要打地基、和水泥、砌牆,那就得找你個幫手了。作爲主線程的我就叫了幾個幫手做我的子線程直到把房子蓋好。

二、線程和進程有什麼不同?

        Windows中,進程是對象和句柄的巨大熔池,飽含所有資源卻什麼都不會做。而在UNIX中,內核黑客們爲進程綁了一個主線程,即進程除了是資源集合外,天生是可以運行的。

        線程則是這巨大池子中的魚,往返穿梭、自由且忙碌,呼吸着、左右着這些資源。

三、Context switch(上下文轉換)的發生。

對同一對象操作是發生context switch是有風險的,    我們稱之爲race condition 競爭條件。

四、Atomic Operations 原子操作應運而生。

用標誌位來隔離多線程也是不科學的,會生產N多行代碼,發生context switch機會很大。原子性應發生在機器碼彙編的級別上。所以我們需要一個不被操作系統中斷的標誌位操作。

五、線程間如何通信?

讓很多人同時在廚房幫你炒幾道菜,通常不是很順利。讓多線程同時處理同一件事情值得我們小心謹慎。

六、HANDLE內核對象需要釋放。

七、線程內核對象與線程的不同?

八、多線程的成功:

保證與主線程有最小的接觸面積。

各線程間的數據要相互分離,避免使用全局變量,避免共同使用GDI對象。

讓主線程處理UI界面。

九、線程的等待:不要在Win32中使用GetExitThread() ,會對系統資源造成嚴重的衝擊。

我們可以用waitSingleObject替代。這兩個函數都在線程核心對象被激發時返回。阻塞等待比每秒訪問幾百萬次某個函數要好得多。

十、什麼是一個被激發的對象?當線程運行時,線程核心對象未激發;當線程結束時,線程核心對象被激發。

十一、       GetExitCodeThread()獲得一個也終止線程的ID

十二、       waitForMultipleObject();同時等待多個監控多個內核對象的激發。

十三、       關於內核對象:

進程在被初始化時,系統爲其分配一個句柄表,此句柄表只用於內核對象。 句柄表的每一項記錄了每個內核對象的信息,所謂信息主要包括:(句柄在句柄表表中的)索引、指向內核對象內存的地址、訪問屏蔽標誌、內核對象句柄繼承標誌

進程在初始化時句柄表是空的,每當進程創建一個內核對象時,系統就在該進程的句柄

表中找出一個空項,設置新創建的內核對象的信息。 內核對象的創建函數幾乎都是形如Cerate*的形式,這些函數返回新創建的內核對象的句柄。這裏返回的所謂句柄,其值實際上是該內核對象在進程句柄表中的索引,用於標識該對象在進程句柄表中的位置

Cerate*函數返回失敗的話,返回值通常爲NULL0),但也有一些是INVALID_HANDLE_VALUE-1)。關閉內核對象通過調用CloseHandle完成,每調用一次,內核對象使用計數遞減1

十四、       msgWaitForMultipleObjects();等待內核對象或消息的激發。

十五、       不要長期鎖定一個資源

十六、       critical section(臨界區) 中如果線程down掉,我們無法取消這個section,如果需要這種機制可使用mutex,我們在監視線程退出時可以進行取消。

十七、       死鎖。哲學家問題,應用Mutex可以解決。

十八、       Mutex(互斥器)上鎖是對內核對象進行操作,花費時間要比critical section長,

        可以跨進程使用。

        可指定等待時間。

十九、       哲學家問題,用WaitForMultipleObjects()可同時等待多隻筷子的到來。

二十、       Semaphore(信號量)可以針對一組相同個體資源,並設立一個最大計數。當計數用完之後,之後的線程就必須等待。可以具名,可被多進程訪問。

二十一、              信號量(semaphore)和互斥器(Mutex)在剛建立時都要將設法不要讓別的線程立即使用。如:信號量裏的create時設數量爲0Mutex中設當前線程佔有Mutex

二十二、              注意EVENT的遺失現象。Event主要用於同步,是核心對象,他的激活它是可控制的,比較方便,多用於IOCP。可具名,被其他進程訪問

第二節 新的線程控制

一、在一個線程中結束另一個線程。

TerminateThread(),會引起內存泄漏。比較危險。

二、Signal(信號)

三、優先級:GetPriorityClass() / SetPriorityClass(); 微調:GetThreadPriority()、SetThreadPriority()

第三節 overlap IO

一、可以同時讀寫文件的許多部分。

二、OVERLAPPED結構體保存了信息。

三、以文件HANDLE作爲激發機制,可用waitForSingleObject()/ GetoverlappedResult()來等待未完的異步事件完成。別切在OVERLAPPED中保存了所需要的信息。

四、OVERLAPPED的末尾設置EVENT結構體,當異步事件完成時,操作系統可以激發次EVENT核心對象。並且採用手動,不讓操作系統自動激發它,導致競爭條件。

從而可實現在等待同一個文件的多個事件好像文件被切割後用事件通知一樣。

五、重疊IO的限制如下:最多同時等待64個事件。在傳輸小於32k的數據是平均要比普通方法多花費15%的時間。

六、IOCP:極大的發掘CPU的速率,對多CPU的服務器很適合。

七、IOCP對線程數的控制。有時可能因爲客觀需要實際線程數大於CPU上最大線程數。

八、IOCP中如果執行線程因爲某事(如文件io)而掛起,則CPu將閒置,故應創建比CPU數多的線程數。

        創建線程數 = 執行中線程數 + 被阻塞線程數 + CP上等待着的後備線程數

九、避免返回Completion Packets。不需要IOCP返回一個包。創建OVERLAPPED結構體,初始化一個manul-reset 手工重置的EVENT結構體,放在OVERLAPPED中,並將最後一位置1.------WIN32多線程程序設計》P182

十、因爲c/c++運行標準庫比多線程出現的早,所以直接用CreateThread()會有同步方面的錯誤。因此,高手們給我們提供了beginThreadEx()來解決這個問題。

十一、       排它鎖:在一個就結構體內部設立一個鎖變量,任何線程訪問時都要開鎖,迫使多線程的同步訪問變成順序訪問,帶來了安全,卻失去了多線程的優勢。

十二、       C++_beginThreadEx()中的參數中要使用unsigned類型,可定義一個typeDefine來轉換。

十三、       C++的成員函數實現線程時,相應函數因爲默認需要一個this指針,但操作系統不知道,扔了一個LRARAM進去。

        解決的辦法,將相應成員函數設爲static。並將this作爲參數。

十四、       C++類中添加Critical Section。可用C++Critical Section對象進行封裝。

十五、       C++錯誤處理,

十六、       MFC中以掛起狀態啓動線程。CWindThread(),AfxBeginThread()

十七、       過程:

a)       創建線程,設參數爲CREATE_SUSPENDED.

b)      設置CWinThread()中的m_bAutoDelet.防止創建失敗後自動DELETE線程句柄。可能會產生race condition錯誤。

c)      調用ResumeThread()激活線程。

十八、       不要再UI線程間共享UI對象。會很卡。

十九、       MFC中的每一步都要做到錯誤檢測

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章