進程與線程;同步與互斥:事件,信號量,臨界區,互斥量

進程


一個正在執行的程序
計算機中正在運行的程序的一個實例
可以分配給處理器並且由處理器執行的一個實體
由一個順序執行的代碼段、一個當前狀態和一組相關係統資源所刻畫的活動單元

進程是操作系統資源分配的基本單位

線程


進程中代碼執行的一個序列

線程是操作系統可以進行運算調度的基本單位

進程、線程的區別


1. 劃分尺度不同。線程是進程的一部分。一個進程至少包含一個線程,可以有多個線程。
2. 資源分配不同。進程是資源分配的基本單位,同一進程的線程共享其進程的代碼、數據及文件等資源,而線程僅擁有自己的寄存器和棧,除了CPU外線程與任何系統資源分配都無關。
3. 地址空間不同。系統在運行時會爲每個進程分配內存空間,進程有獨立的地址空間,但線程沒有,多個線程共享內存。
4. 執行過程不同。每個獨立的線程有一個程序運行的入口、順序執行序列和程序出口。但線程卻不能獨立執行,需要依附於應用程序。

同步


同步是指線程之間的一種制約關係,線程A的執行需要線程B的消息,在沒有收到線程B的消息時應等待,直到消息到達。

事件


事件是一個內核對象,可以跨進程使用。

事件被分爲:手動置位和自動置位。手動置位是同時向所有等待線程發信號通知,某一操作已經做完了,使他們都處於有信號的狀態,都成爲可調度線程;自動置位是向某一線程發信號,使它爲有信號狀態,成爲可調度線程。

創建事件
/*
	lpEventAttributes 事件的安全級別,設爲NULL爲默認設置
	bManualReset 人工置位爲true,自動置位爲false
	bInitialState 事件初始化的狀態,有狀態爲true,無狀態爲false
	lpName 事件的名稱,設爲NULL則爲匿名
*/
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,
                   BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName);

設置事件爲有狀態
BOOL SetEvent(HANDLE hEvent);
對於手動置位的事件,SetEvent方法將解鎖在該事件上等待的所有線程,即當人工重置變爲有信號時,所有的等待該事件的線程都變爲可調度線程,將保持有信號狀態,直到某事件手動置位爲無狀態。對於自動置位的事件,SetEvent方法將僅解鎖一個線程,通過調用WaitForSingleObject()自動調用Reset()方法使事件變爲無信號狀態。

設置事件爲無狀態
BOOL ResetEvent(HANDLE hEvent);

信號量


信號量是內核對象,可用於進程間的同步也可用於同一進程中的線程間的同步,用來對資源進行計數。當資源數大於零,信號量處於觸發狀態;當資源是等於零,信號量未觸發。

創建信號量
/*
	lpSemaphoreAttributes 信號量的安全屬性,設爲NULL則爲默認設置
	lInitialCount 初始資源數,必須大於等於零,小於最大資源數
	lMaximumCount 最大資源數
	lpName 信號量名稱,設爲NULL則爲匿名信號量
*/
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, 
LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);

打開一個已有信號量
/*
	dwDesiredAccess 訪問方式,一般使用SEMAPHORE_ALL_ACCESS
	bInheritHandle 繼承特性,一般使用true
	lpName 信號量名稱
*/
HANDLE OpenSemaphore(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);

釋放信號量
/*
	hSemaphore 要釋放的信號量句柄
	lReleaseCount 釋放的數量,即資源的增加量,必須大於零
	lpPreviousCount 原先的計數值,設爲NULL爲不需要傳入
*/
BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);

互斥


對於共享的資源,每個進程訪問時具有排他性。對於共享資源任何時刻僅允許一個線程訪問,其他線程想要訪問則必須等待,直到佔用資源的線程釋放了該資源。互斥可以認爲是一種特殊的同步。

臨界區


臨界區保護一段代碼不被多於一個線程訪問。

臨界區相關函數
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 初始化臨界區
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 進入臨界區
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 離開臨界區
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 刪除臨界區

因爲主線程擁有線程所有權,所以可以重複多次進入臨界區,導致子線程在接受參數之前主線程可能已經修改了參數,而無法實現線程同步。

互斥量


互斥量是一個內核對象,用來確保資源僅被一個線程訪問,可以跨進程訪問。

創建互斥量
/*
        lpMutexAttributes 安全控制,設爲NULL則爲默認設置
        bInitialOwner 是否成爲該互斥量的初始擁有者,設爲TRUE爲擁有,互斥量爲無信號狀態;設爲FALSE爲不擁有,該信號量不爲任何線程佔有,互斥量爲有信號狀態
        lpName 互斥量名稱
*/
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName);

打開互斥量
/*
        dwDesiredAccess 訪問方式,一般設爲MUTEX_ALL_ACCESS
        bInheritHandle 該進程的子進程能否繼承該互斥量,一般設爲TRUE
        lpName 互斥量名稱
*/
HANDLE OpenMutex(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);

釋放互斥量
BOOL ReleaseMutex(HANDLE hMutex);

互斥量同臨界區一樣,主線程擁有線程控制權,因此同樣不能用於同步。
互斥量可以解決因線程意外終止而造成的遺棄現象。具體來說,如果一個線程在釋放互斥量之前因某些意外終止,照理來說應該互斥量還要能夠被其他等待的線程使用,否則會陷入無限的等待,這是不合理的。因此,在這樣的情況下,系統會將互斥量的狀態設爲有信號狀態,這樣其他線程就可以使用了。


小結


事件:用於通知其他線程事件已發生,從而啓動線程
信號量:可以對資源進行計數,允許多個線程共享資源,限制了同一時刻多個線程能訪問的最大資源數。
臨界區:在任一時刻僅允許一個線程使用臨界區資源。四者中僅有臨界區不是內核對象。適合於數據訪問的控制。
互斥量:擁有互斥量纔可以訪問共享資源,因此共享資源不會被多個線程所共享。

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