Windows線程同步(一):臨界區對象

爲什麼使用線程同步?

同步可以保證在一個時間內只有一個線程對某個資源(如操作系統資源等共享資源)有控制權。共享資源包括全局變量、公共數據成員或者句柄等。同步還可以使得有關聯交互作用的代碼按一定的順序執行。

線程同步的方式?

同步對象有:CRITICAL_SECTION (臨界區),Event(事件),Mutex(互斥對象),Semaphores(信號量)。

本文重點講解CRITICAL_SECTION (臨界區)。

臨界區,說白了,就是“鎖”。看過星爺的《破壞王》的朋友都知道,那個送外賣的小子,就是靠自創絕招“無敵風火輪”將大師兄打敗,抱得美人歸。“無敵風火輪”的本質就是:鎖!

怎麼鎖?

這裏有四個關鍵函數:InitializeCriticalSection  EnterCriticalSection  LeaveCriticalSection  DeleteCriticalSection來完成此機制。

使用臨界區對象的時候,首先要定義一個臨界區對象CriticalSection:
CRITICAL_SECTION CriticalSection;

然後,初始化該對象:InitializeCriticalSection(&CriticalSection);

如果一段程序代碼需要對某個資源進行同步保護,則這是一段臨界區代碼。在進入該臨界區代碼前調用EnterCriticalSection函數,這樣,其他線程都不能執行該段代碼,若它們試圖執行就會被阻塞。

完成臨界區的執行之後,調用LeaveCriticalSection函數,其他的線程就可以繼續執行該段代碼。


簡要實例

下面的代碼中,如果不加CRITICAL_SECTION ,有可能造成在線程1給data設置完名字後,線程2給data設置年齡,造成了數據紊亂,所以有必要使用同步機制,將其鎖住,保證數據的安全。

class Data
{
private:
	CString Name;
	int Age;
public:
	void SetName(const CString& name)
	{
		Name = name;
	}
	
	void SetAge(int age)
	{
		Age = age;
	}
	
	void GetName(CString &name)
	{
		name = Name;
	}
	
	void GetAge(int &age)
	{
		age = Age;
	}
};

Data g_data; //全局變量
CRITICAL_SECTION CriticalSection; 

//線程函數
DWORD WINAPI ThreadProc( LPVOID lpParameter )
{
	EnterCriticalSection(&CriticalSection); 
	data.SetName("趙星星");
	data.SetAge(20);
	LeaveCriticalSection(&CriticalSection);
}

int main()
{

    InitializeCriticalSection(&CriticalSection); 
	
    //創建線程,執行線程函數
	//......
	
	DeleteCriticalSection(&CriticalSection);

	return 0;
}
真鎖?假鎖?

可以定義CRITICAL_SECTION 數組:CRITICAL_SECTION g_Critical[10];

CRITICAL_SECTION 沒有超時的概念,如果函數LeaveCriticalSection不被調用,則其他線程將無限期的等待。容易造成死鎖。

CRITICAL_SECTION 屬於輕量級的線程同步對象,相對於mutex來說,它的效率會高很多。mutex可以用於進程之間的同步,CRITICAL_SECTION只在同一個進程有效。

實際上,CRITICAL_SECTION 鎖的是代碼段,如果代碼段中有對資源的佔用,只是間接的鎖住了該資源,我們也可以稱之爲“假鎖”。


參考:

1、《MFC教程》

2、 csdn精彩討論



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