第一篇:操作系統(tǒng)-創(chuàng)建線程,利用互斥實現(xiàn)線程共享變量通信介紹
2016-2017學(xué)年度第一學(xué)期大作業(yè)
課程名稱:
操作系統(tǒng)(含課程設(shè)計)
任課教師:
解
曉
萌
作業(yè)題目:
創(chuàng)建線程,利用互斥實現(xiàn)線程共享變量通信
姓
名:
魯
斌
學(xué)
號:
20***0
2專
業(yè):
計算機科學(xué)與技術(shù)
教學(xué)中心:
寶 安 學(xué) 文
聯(lián)系電話:
***
評審日期__________成績_________評審教師(簽名)__________
華南理工大學(xué)網(wǎng)絡(luò)教育學(xué)院
“計算機操作系統(tǒng)”課程設(shè)計大作業(yè)
實驗報告
一、題目: 創(chuàng)建線程,利用互斥實現(xiàn)線程共享變量通信
二、目的
掌握線程創(chuàng)建和終止,加深對線程和進程概念的理解,會用同步與互斥方法實現(xiàn)線程之間的通信。
三、概述:
為了確保讀線程讀取到的是經(jīng)過修改的變量,必須在向變量寫入數(shù)據(jù)時禁止其他線程對它的任何訪問,直至賦值過程結(jié)束后再解除對其他線程的訪問限制。這保證了線程了解其他線程任務(wù)處理結(jié)束后的結(jié)果而采取的保護措施稱為線程同步。
從大的方面來講,線程的同步分為用戶模式的線程同步和內(nèi)核對象的線程同步。用戶模式中線程的同步方法有原子訪問和臨界區(qū)等方法。它的特點是同步速度特別快,適合對線程運行速度有嚴(yán)格要求的場合。
內(nèi)核對象的線程同步由事件、等待定時器、信號量以及信號燈等內(nèi)核對象構(gòu)成。由于這同步機制使用了內(nèi)核對象,使用時一定要將線程從用戶模式切換到內(nèi)核模式,而這種轉(zhuǎn)換一般要耗費近千個CPU周期,所以同步速度較慢,但適用性卻要遠優(yōu)于用戶模式的線程 臨界區(qū)
臨界區(qū)是一段獨占對某些共享資源訪問的代碼,在任意時刻只允許一個線程對共享資源進行訪問。通過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數(shù)據(jù)訪問若有多個線程試圖同時訪問臨界區(qū),那么在有一個線程進入后其他所有試圖訪問此臨界區(qū)的線程將被掛起,并一直持續(xù)到進入臨界區(qū)的線程離開。臨界區(qū)在被釋放后,其他線程可繼續(xù)搶占,并以此達到用原子方式操作共享資源的目的。
使用臨界區(qū)保持線程同步
以下是通過一段代碼說明了臨界區(qū)在保護多線程訪問共享資源中的作用。通過兩個線程分別對全局變量g_cArray[10]進行寫入操作,用臨界區(qū)結(jié)構(gòu)對象g_cs來保持線程的同步,并在開啟線程前對它進行初始化。為了使實驗效果更
明顯,體現(xiàn)出臨界區(qū)的作用,在線程函數(shù)對共享資源g_cArray[10]的寫入時,以Sleep()函數(shù)延遲1毫秒,令其他線程同它搶占CPU的可能性加大。若不用臨界區(qū)對它進行保護,則共享資源數(shù)據(jù)將被破壞,但使用臨界區(qū)對線程保持同步后就可得到正確的結(jié)果。代碼如下:
// 臨界區(qū)結(jié)構(gòu)對象 CRITICAL_SECTION g_cs;// 共享資源 char g_cArray[10];UINT ThreadProc10(LPVOID pParam){ // 進入臨界區(qū)
EnterCriticalSection(&g_cs);// 對共享資源進行寫入操作
for(int i = 0;i < 10;i++){
g_cArray[i] = 'a';
Sleep(1);} // 離開臨界區(qū)
LeaveCriticalSection(&g_cs);return 0;} UINT ThreadProc11(LPVOID pParam){ // 進入臨界區(qū)
EnterCriticalSection(&g_cs);// 對共享資源進行寫入操作
for(int i = 0;i < 10;i++){
g_cArray[101] = 'b';
Sleep(1);} // 離開臨界區(qū)
LeaveCriticalSection(&g_cs);return 0;} // 臨界區(qū)結(jié)構(gòu)對象 CRITICAL_SECTION g_cs;// 共享資源 char g_cArray[10];UINT ThreadProc10(LPVOID pParam){ // 進入臨界區(qū)
EnterCriticalSection(&g_cs);// 對共享資源進行寫入操作
for(int i = 0;i < 10;i++){
g_cArray[i] = 'a';
Sleep(1);} // 離開臨界區(qū)
LeaveCriticalSection(&g_cs);return 0;} UINT ThreadProc11(LPVOID pParam){ // 進入臨界區(qū)
EnterCriticalSection(&g_cs);
// 對共享資源進行寫入操作
for(int i = 0;i < 10;i++){
g_cArray[101] = 'b';
Sleep(1);} // 離開臨界區(qū)
LeaveCriticalSection(&g_cs);return 0;} ……
void CSample08View::OnCriticalSection(){ // 初始化臨界區(qū)
InitializeCriticalSection(&g_cs);// 啟動線程
AfxBeginThread(ThreadProc10, NULL);AfxBeginThread(ThreadProc11, NULL);// 等待計算完畢
Sleep(300);// 報告計算結(jié)果
CString sResult = CString(g_cArray);AfxMessageBox(sResult);}
信號量內(nèi)核對象
信號量內(nèi)核,允許多個線程在同一時刻訪問同一資源,但需限制在同一時刻訪問此資源的最大線程數(shù)目。在用CreateSemaphore()創(chuàng)建信號量時應(yīng)要同時指出允許的最大資源計數(shù)和當(dāng)前可用資源計數(shù)。一般將當(dāng)前可用資源計數(shù)設(shè)
為最大資源計數(shù),每增一個線程對共享資源的訪問,當(dāng)前可用資源計數(shù)就減1,只要當(dāng)前可用資源計數(shù)大于0的,就可發(fā)出信號量信號。但當(dāng)前可用計數(shù)減小到0時則說明當(dāng)前占用資源的線程數(shù)已達到了所允許的最大數(shù)目,不能在允許其他線程的進入,這時的信號量信號將無法發(fā)出。線程在處理完共享資源后,應(yīng)在離開的同時通過ReleaseSemaphore()函數(shù)將當(dāng)前可用資源計數(shù)加1。在任何時候當(dāng)前可用資源計數(shù)決不能大于最大資源計數(shù)。
使用信號量內(nèi)核對象進行線程同步主要會用到OpenSemaphore()、ReleaseSemaphore()、CreateSemaphore()、WaitForMultipleObjects()和WaitForSingleObject()等函數(shù)。其中,CreateSemaphore()是用來創(chuàng)建一個信號量內(nèi)核對象,其函數(shù)原型為:
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 安全屬性指針
LONG lInitialCount, // 初始計數(shù)
LONG lMaximumCount, // 最大計數(shù)
LPCTSTR lpName // 對象名指針);參數(shù)lMaximumCount是一個有符號32位值,定義了允許的最大資源計數(shù),最大取值不超過4294967295。lpName參數(shù)可為創(chuàng)建的信號量定義一個名字,由于其創(chuàng)建的是一個內(nèi)核對象,所以在其他進程中可通過該名字而得到此信號量。OpenSemaphore()函數(shù)即可用來根據(jù)信號量名打開在其他進程中創(chuàng)建的信號量,函數(shù)原型如下:
HANDLE OpenSemaphore(DWORD dwDesiredAccess, // 訪問標(biāo)志
BOOL bInheritHandle, // 繼承標(biāo)志
LPCTSTR lpName // 信號量名);在線程離開對共享資源的處理時,一定要通過ReleaseSemaphore()來增加當(dāng)前可用資源計數(shù)。否則將會導(dǎo)致當(dāng)前正在處理共享資源的實際線程數(shù)并不能達到要限制的數(shù)值,而其他線程卻因為當(dāng)前可用資源計數(shù)為0但仍無法進入的情況。ReleaseSemaphore()的函數(shù)原型為:
BOOL ReleaseSemaphore(HANDLE hSemaphore, // 信號量句柄
LONG lReleaseCount, // 計數(shù)遞增數(shù)量
LPLONG lpPreviousCount // 先前計數(shù));互斥是用途廣泛的內(nèi)核對象。能保證多個線程對同一共享資源的互斥訪問。只有擁有互斥對象的線程才具有訪問資源的權(quán)限,由于互斥對象只有一個,所以就決定了無論在什么情況下,這共享資源都不會同時被多個線程所訪問。當(dāng)前占據(jù)資源的線程在任務(wù)處理完后應(yīng)將擁有的互斥對象交出,便于其他線程在獲得后得以訪問資源?;コ鈱ο笤诓僮飨到y(tǒng)中擁有特殊代碼,并由操作系統(tǒng)來管理,操作系統(tǒng)甚至還允許它進行一些其他內(nèi)核對象不能進行的非常規(guī)操作。為了便于理解,可參照互斥內(nèi)核
用互斥內(nèi)核對象來保持線程同步可能用到的函數(shù)有OpenMutex()、ReleaseMutex()、CreateMutex()、WaitForSingleObject()和WaitForMultipleObjects()等。
在使用互斥對象前,首先要通過CreateMutex()或OpenMutex()創(chuàng)建或打開一個互斥對象。CreateMutex()函數(shù)原型為:
// 互斥對象
HANDLE hMutex = NULL;har g_cArray[10];UINT ThreadProc18(LPVOID pParam){ // 等待互斥對象通知
WaitForSingleObject(hMutex, INFINITE);// 對共享資源進行寫入操作
for(int i = 0;i < 10;i++){
g_cArray[i] = 'a';
Sleep(1);} // 釋放互斥對象
ReleaseMutex(hMutex);return 0;} UINT ThreadProc19(LPVOID pParam){ // 等待互斥對象通知
WaitForSingleObject(hMutex, INFINITE);// 對共享資源進行寫入操作
for(int i = 0;i < 10;i++){
g_cArray[101] = 'b';
Sleep(1);} // 釋放互斥對象
ReleaseMutex(hMutex);return 0;} ……
void CSample08View::OnMutex(){ // 創(chuàng)建互斥對象
hMutex = CreateMutex(NULL, FALSE, NULL);// 啟動線程
AfxBeginThread(ThreadProc18, NULL);AfxBeginThread(ThreadProc19, NULL);// 等待計算完畢
Sleep(300);// 報告計算結(jié)果
CString sResult = CString(g_cArray);AfxMessageBox(sResult);}// MFC互斥類對象
CMutex g_clsMutex(FALSE, NULL);UINT ThreadProc27(LPVOID pParam){ // 等待互斥對象通知
g_clsMutex.Lock();// 對共享資源進行寫入操作
for(int i = 0;i < 10;i++){
g_cArray[i] = 'a';
Sleep(1);} // 釋放互斥對象
g_clsMutex.Unlock();return 0;} UINT ThreadProc28(LPVOID pParam){ // 等待互斥對象通知
g_clsMutex.Lock();// 對共享資源進行寫入操作
for(int i = 0;i < 10;i++){
g_cArray[101] = 'b';
Sleep(1);
} // 釋放互斥對象
g_clsMutex.Unlock();return 0;} ……
void CSample08View::OnMutexMfc(){ // 啟動線程
AfxBeginThread(ThreadProc27, NULL);AfxBeginThread(ThreadProc28, NULL);// 等待計算完畢
Sleep(300);// 報告計算結(jié)果
CString sResult = CString(g_cArray);AfxMessageBox(sResult);} 設(shè)計體會
1、線程能更好地提高程序的并行執(zhí)行程度,充分地發(fā)揮多處理機的優(yōu)越性。
2、線程減少了程序并發(fā)執(zhí)行時所付出的時空開銷,使OS具有更好的并發(fā)性。
3、線程的使用使程序處理更快更靈活,而這靈活同樣也帶來各種不確定性的可能。特別是在多個線程對同一公共變量進行訪問時,雖然未使用線程同步的程序代碼在邏輯上可能沒有什么問題,但為了確保程序的正確、可靠運行,一定要在適當(dāng)?shù)膱龊喜扇【€程同步措施。
4.線程有效地提高系統(tǒng)資源的利用率和系統(tǒng)的吞吐量。