實驗三 進程同步實驗_第1頁
實驗三 進程同步實驗_第2頁
實驗三 進程同步實驗_第3頁
實驗三 進程同步實驗_第4頁
實驗三 進程同步實驗_第5頁
已閱讀5頁,還剩10頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、實驗三 進程同步機制一、實驗內(nèi)容: 學(xué)習(xí)Windows有關(guān)進程/線程同步的背景知識和API,學(xué)習(xí)windows平臺下常用的同步方式,并分析2個實驗程序(利用信號量實現(xiàn)兩個進程間的同步和利用互斥量實現(xiàn)讀者寫者問題),觀察程序的運行情況并分析執(zhí)行結(jié)果。二、實驗?zāi)康? 在本實驗中,通過對互斥量(Mutex)和信號量(Semaphore)對象的了解,來加深對Windows 進程、線程同步的理解。(1) 了解互斥量和信號量對象。(2) 通過分析實驗程序,理解管理信號量對象的API。(3) 理解在進程中如何使用信號量對象。(4) 通過分析實驗程序,理解在線程中如何使用互斥量對象。(5) 理解父進程創(chuàng)建子進

2、程的程序設(shè)計方法,理解在主線程中創(chuàng)建子線程的方法。三、實驗要求:(1) 理解Windows有關(guān)進程/線程同步的背景知識和API。(2) 按要求運行2個程序,觀察程序執(zhí)行的結(jié)果,并給出要求的結(jié)果分析。(3) 參照3-2程序,寫出一個實現(xiàn)單個生產(chǎn)者消費者問題的算法,可以使用單個緩沖區(qū),也可以使用緩沖池,生產(chǎn)者隨機產(chǎn)生任意形式的數(shù)據(jù)并放入緩沖區(qū)中,消費者則以隨機的時間間隔從緩沖區(qū)中取數(shù)據(jù),隨機時間請使用隨機數(shù)產(chǎn)生。四、并發(fā)與同步的背景知識Windows開發(fā)人員可以使用同步對象來協(xié)調(diào)線程和進程的工作,以使其共享信息并執(zhí)行任務(wù)。此類對象包括互斥量Mutex、信號量Semaphore、事件Event等。多

3、進程、多線程編程中關(guān)鍵的一步是保護所有的共享資源,工具主要有互斥量Mutex和信號量Semaphore等;另一個是協(xié)調(diào)線程使其完成應(yīng)用程序的任務(wù),為此,可利用內(nèi)核中的信號量對象或事件對象。互斥量是一個可命名且安全的內(nèi)核對象,主要目的是引導(dǎo)對共享資源的訪問。擁有單一訪問資源的線程創(chuàng)建互斥體,所有希望訪問該資源的線程應(yīng)該在實際執(zhí)行操作之前獲得互斥體,而在訪問結(jié)束時立即釋放互斥體,以允許下一個等待線程獲得互斥體,然后接著進行下去。利用CreateMutex() API可創(chuàng)建互斥量,創(chuàng)建時可以指定一個初始的擁有權(quán)標志,通過使用這個標志,只有當線程完成了資源的所有的初始化工作時,才允許創(chuàng)建線程釋放互斥體

4、。為了獲得互斥體,首先,想要訪問調(diào)用的線程可使用OpenMutex() API來獲得指向?qū)ο蟮木浔蝗缓?,線程將這個句柄提供給一個等待函數(shù)。當內(nèi)核將互斥體對象發(fā)送給等待線程時,就表明該線程獲得了互斥體的擁有權(quán)。當線程獲得擁有權(quán)時,線程控制了對共享資源的訪問必須設(shè)法盡快地放棄互斥體。放棄共享資源時需要在該對象上調(diào)用ReleaseMutex() API。然后系統(tǒng)負責(zé)將互斥量擁有權(quán)傳遞給下一個等待著的線程 (由到達時間決定順序) 。信號量Semaphore與互斥量Mutex的用法不同,互斥量Mutex保證任意時刻只能有一個進程或線程獲得互斥體,信號量允許多個線程同時使用共享資源,這與操作系統(tǒng)中的Wa

5、it/Signal操作【也稱PV操作】相同。它指出了同時訪問共享資源的線程最大數(shù)目。它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數(shù)目。在用CreateSemaphore()創(chuàng)建信號量時即要同時指出允許的最大資源計數(shù)和當前可用資源計數(shù)。一般是將當前可用資源計數(shù)設(shè)置為最大資源計數(shù)或者0。每增加一個線程對共享資源的訪問,當前可用資源計數(shù)就會減1,只要當前可用資源計數(shù)是大于0的,就可以發(fā)出信號量信號。但是當前可用計數(shù)減小到0時則說明當前占用資源的線程數(shù)已經(jīng)達到了所允許的最大數(shù)目,不能在允許其他線程的進入,此時的信號量信號將無法發(fā)出。線程在處理完共享資源后,應(yīng)在離開的

6、同時通過ReleaseSemaphore()函數(shù)將當前可用資源計數(shù)加1。在任何時候當前可用資源計數(shù)決不可能大于最大資源計數(shù)。 此外,windows還提供了另外一個容易誤導(dǎo)大家理解的同步對象,取名為Critical Section,中文取名為臨界區(qū),請大家注意與課本講的臨界資源、臨界區(qū)的概念相區(qū)分。課本上臨界區(qū)指“對臨界資源進行訪問的代碼”;而這種稱為“Critical Section”互斥機制,并不是這個意思,而是訪問臨界區(qū)之前的一種加鎖機制,與互斥量Mutex的作用類似,只是“Critical Section”互斥機制只能在同一進程內(nèi)部各個線程間使用,而Mutex互斥機制是可以跨進程使用的。

7、五、實驗步驟1. 信號量Semaphore對象清單3-1程序展示如何在進程間使用信號量對象。父進程啟動時,利用CreateSemaphore () API創(chuàng)建一個命名的、可共享的信號量對象,并利用CreateProcess()創(chuàng)建子進程,然后調(diào)用WaitForSingleObject()函數(shù)去獲取信號量,但是由于信號量的初始值為0,所以父進程阻塞在此,無法成功占有信號量;子進程創(chuàng)建后,調(diào)用OpenSemaphore()打開父進程創(chuàng)建的信號量,然后調(diào)用ReleaseSemaphore()函數(shù)釋放了1個信號量,此后,處于阻塞狀態(tài)的父進程獲取了子進程釋放的信號量,從而解除了阻塞,繼續(xù)運行至程序結(jié)束。

8、清單3-1 創(chuàng)建和打開信號量對象在進程間傳送信號/ Semaphore信號量項目# include <windows.h># include <stdio.h># include <iostream.h>/ 定義一個信號量的名字static LPCTSTR g_szSemaphoreName ="shmtu.os2012.semaphore"/ 本方法只是創(chuàng)建了一個進程的副本,以子進程模式 (由命令行指定) 工作BOOL CreateChild()/ 提取當前可執(zhí)行文件的文件名TCHAR szFilenameMAX_PATH ; GetM

9、oduleFileName(NULL, szFilename, MAX_PATH) ; / 格式化用于子進程的命令行,指明它是一個EXE文件和子進程 TCHAR szCmdLineMAX_PATH ; sprintf(szCmdLine, ""%s" child" , szFilename) ; / 子進程的啟動信息結(jié)構(gòu) STARTUPINFO si; ZeroMemory(reinterpret_cast<void*>(&si), sizeof(si) ; si.cb = sizeof(si);/ 必須是本結(jié)構(gòu)的大小 / 返回的子進

10、程的進程信息結(jié)構(gòu) PROCESS_INFORMATION pi; / 使用同一可執(zhí)行文件和告訴它是一個子進程的命令行創(chuàng)建進程 BOOL bCreateOK = CreateProcess(szFilename,/ 生成的可執(zhí)行文件名szCmdLine, / 指示其行為與子進程一樣的標志 NULL,/ 子進程句柄的安全性 NULL,/ 子線程句柄的安全性 FALSE,/ 不繼承句柄 CREATE_NEW_CONSOLE,/ 特殊的創(chuàng)建標志 NULL,/ 新環(huán)境 NULL,/ 當前目錄 &si,/ 啟動信息結(jié)構(gòu) &pi ) ;/ 返回的進程信息結(jié)構(gòu) / 釋放對子進程的引用 if (

11、bCreateOK) CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return(bCreateOK) ;/ 下面的方法創(chuàng)建一個信號量和一個子進程,然后等待子進程在返回前釋放一個信號void WaitForChild() HANDLE hSemaphore = CreateSemaphore( /創(chuàng)建一個信號量,初始值0,最大值為1 NULL, / 缺省的安全性,子進程將具有訪問權(quán)限 0, /初始值0 1, /最大值為1 g_szSemaphoreName /信號量名稱 ); if (hSemaphore != NULL)cout <

12、;< " 信號量對象已經(jīng)建立啦。" << endl;/ 創(chuàng)建子進程if ( CreateChild()cout << " 父進程建立了一個子進程" << endl;/ 等待,直到子進程發(fā)出信號cout << "因為當前信號量的值為0,所以父進程暫時阻塞在此啦." << endl;WaitForSingleObject(hSemaphore, INFINITE);cout << "因為子進程釋放了1個信號量,所以,父進程可以解除阻塞啦。"

13、<< endl; / 清除句柄 CloseHandle(hSemaphore); hSemaphore=INVALID_HANDLE_VALUE; / 以下方法在子進程模式下被調(diào)用,其功能只是釋放1個信號量void SignalParent() / 嘗試打開句柄 cout << "child process begining." << endl; HANDLE hSemaphore = OpenSemaphore( SEMAPHORE_ALL_ACCESS,/ 所要求的最小訪問權(quán)限 FALSE,/ 不是可繼承的句柄 g_szSemapho

14、reName);/ 信號量名稱 if(hSemaphore != NULL)cout<<"如果你同意釋放一個信號量,請按任意鍵"<<endl;getchar();cout << "此刻,子進程釋放了1個信號量." << endl; ReleaseSemaphore(hSemaphore,1,NULL); / 清除句柄 CloseHandle(hSemaphore) ; hSemaphore = INVALID_HANDLE_VALUE;int main(int argc, char* argv ) / 檢查

15、父進程或是子進程是否啟動 if (argc>1 && strcmp(argv1 , "child" )= 0) / 向父進程發(fā)出信號 SignalParent() ; cout << "子進程馬上就要運行結(jié)束了。請按任意鍵繼續(xù)。" << endl ; else / 創(chuàng)建一個信號量并等待子進程 WaitForChild(); cout << "父進程馬上就要運行結(jié)束了。請按任意鍵繼續(xù)。" << endl ; getchar(); return 0;步驟1:編譯并執(zhí)行3

16、-1.exe程序。程序運行結(jié)果是 (分行書寫) : _ _ _ _ _ _閱讀和分析程序3-1,請回答:(1) 程序中,創(chuàng)建一個信號量使用了哪一個系統(tǒng)函數(shù)?創(chuàng)建時設(shè)置的信號量初始值是多少,最大值是多少?a. _b. _(2) 創(chuàng)建一個進程 (子進程) 使用了哪一個系統(tǒng)函數(shù)?_(3) 從步驟1的輸出結(jié)果,對照分析3-1程序,能夠看出程序運行的流程嗎?請簡單描述:_步驟2:編譯程序生成執(zhí)行文件3-1.exe,在命令行狀態(tài)下執(zhí)行程序,分別使用格式:(1) 3-1 child(2) 3-1 或3-1 *運行程序,記錄執(zhí)行的結(jié)果,并分行說明產(chǎn)生不同結(jié)果的原因。2. 互斥量Mutex對象注意:多線程編程需

17、要在Visual C+中設(shè)定多線程C運行時庫。打開你的工程項目后,在Visual C+的“Project”菜單下面,選擇“Settings”菜單,如下兩圖所示,可以分別設(shè)定Debug版本和Release版本所使用的多線程C運行時庫,以Debug開頭的都是為Debug版本準備的,都選Multithread版本。如果使用標準 C 庫而調(diào)用VC運行時庫函數(shù),則在程序的link階段會提示如下錯誤:error LNK2001: unresolved external symbol _endthreadexerror LNK2001: unresolved external symbol _beginth

18、readex清單3-2的程序中是讀者寫者問題的一個實現(xiàn),滿足讀者優(yōu)先原則,使用同步機制的互斥量實現(xiàn),對每個讀者和寫者分別用一個線程來表示。測試數(shù)據(jù)文件的數(shù)據(jù)格式說明:測試數(shù)據(jù)文件包括n行測試數(shù)據(jù),每行描述創(chuàng)建的是用于產(chǎn)生讀者還是寫者的數(shù)據(jù)。每行測試數(shù)據(jù)包括4個字段,各字段間用空格分隔。l 第一字段為線程序號。l 第二字段表示相應(yīng)線程角色,W表示寫者,R表示讀者。l 第三字段為線程延遲。l 第四字段為線程讀寫操作持續(xù)時間。清單3-2 利用互斥量Mutex實現(xiàn)讀者寫者問題#include "windows.h"#include "process.h"#inc

19、lude <conio.h>#include <stdlib.h>#include <fstream.h>#include <io.h>#include <string.h>#include <stdio.h>#define READER 'R' / 讀者#define WRITER 'W' / 寫者#define INTE_PER_SEC 1000 / 每秒時鐘中斷數(shù)目#define MAX_THREAD_NUM 64 / 最大線程數(shù)目#define MAX_FILE_NUM 32 / 最

20、大數(shù)據(jù)文件數(shù)目#define MAX_STR_LEN 32 / 字符串長度volatile int readcount = 0; / 讀者數(shù)目HANDLE RP_Write;struct ThreadInfo / 定義線程數(shù)據(jù)結(jié)構(gòu)int serial; / 線程序號char entity; / 線程類別(判斷是讀者線程還是寫者線程)double delay; / 線程延遲double persist; / 線程讀寫操作持續(xù)時間;/ 讀者優(yōu)先讀者線程/ p:讀者線程信息unsigned int _stdcall RP_ReaderThread(void *p)/ 互斥變量HANDLE h_Mut

21、ex;h_Mutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount");DWORD wait_for_mutex; /等待互斥變量所有權(quán)DWORD m_delay; /延遲時間DWORD m_persist; /讀文件持續(xù)時間int m_serial; /線程序號/從參數(shù)中獲得信息m_serial = (ThreadInfo *)(p)->serial;m_delay = (DWORD)(ThreadInfo *)(p)->delay*INTE_PER_SEC);m_persist = (DWOR

22、D)(ThreadInfo*)(p)->persist*INTE_PER_SEC);Sleep (m_delay) ; /延遲等待printf("Reader thread %d sents the reading require.n",m_serial);/等待互斥信號,保證對readcount的訪問、修改互斥wait_for_mutex = WaitForSingleObject(h_Mutex,-1);/ 讀者數(shù)目增加readcount+;if(readcount =1)/這是第一個讀者,第二個讀者到來時,readcount為2,if的條件不滿足,不會進入if語

23、句內(nèi)部執(zhí)行/這是第一個讀者,如果此刻沒有寫者正在寫,則RP_Write信號量狀態(tài)為可用(未占用),那它就必須先占用(鎖定)RP_Write信號量,這就實現(xiàn)了讀-寫互斥/如果此刻有寫者正在寫,則RP_Write信號量被寫者占用(鎖定),讀者想對RP_Write加鎖就會阻塞在此,等待RP_Write信號量釋放后,才能繼續(xù)運行WaitForSingleObject(RP_Write, INFINITE);ReleaseMutex(h_Mutex) ; /釋放互斥信號/ 讀文件printf("Reader thread %d begins to read file.n",m_ser

24、ial);Sleep(m_persist) ;/ 退出線程printf("Reader thread %d finished reading file.n",m_serial);/等待互斥信號,保證對readcount的訪問、修改互斥wait_for_mutex = WaitForSingleObject(h_Mutex,-1) ;/讀者數(shù)目減少readcount- ;if(readcount = 0)/如果所有讀者讀完,則釋放RP_Write信號量;此刻若有寫者正在等待(處于阻塞狀態(tài)),將(自動)喚醒寫者ReleaseMutex(RP_Write);ReleaseMute

25、x(h_Mutex) ; /釋放互斥信號return 0;/ 讀者優(yōu)先寫者線程/ p:寫者線程信息unsigned int _stdcall RP_WriterThread(void* p)DWORD m_delay; /延遲時間DWORD m_persist; /寫文件持續(xù)時間int m_serial; /線程序號/從參數(shù)中獲得信息m_serial = (ThreadInfo *)(p)->serial;m_delay = (DWORD)(ThreadInfo *)(p)->delay*INTE_PER_SEC) ;m_persist = (DWORD)(ThreadInfo *

26、)(p)->persist*INTE_PER_SEC) ;Sleep (m_delay); /延遲等待printf("Writer thread %d sents the writing require.n",m_serial);/ 寫者在進行寫數(shù)據(jù)之前,必須確定沒有其它寫者正在寫,也沒有其它讀者在讀,/ 通過RP_Write互斥量實現(xiàn),若有其它寫者正在寫或其它讀者在讀,則該寫者調(diào)用“WaitForSingleObject(RP_Write, INFINITE);”后將阻塞在此/ 等待RP_Write信號量釋放后,才能夠繼續(xù)向下執(zhí)行。WaitForSingleObje

27、ct(RP_Write, INFINITE);/ 寫文件printf("Writer thread %d begins to write to the file.n",m_serial);Sleep(m_persist) ;/ 退出線程printf("Writer thread %d finished writing to the file.n",m_serial);/寫者寫完后,需要釋放RP_Write信號量資源ReleaseMutex(RP_Write);return 0;/ 讀者優(yōu)先處理函數(shù)/ file:文件名void ReaderPriority

28、(char *file)int i;DWORD n_thread = 0; / 線程數(shù)目UINT thread_ID; / 線程IDDWORD wait_for_all; / 等待所有線程結(jié)束/ 互斥對象HANDLE h_Mutex;h_Mutex = CreateMutex(NULL,FALSE,"mutex_for_readcount");/ 線程對象的數(shù)組HANDLE h_ThreadMAX_THREAD_NUM ;ThreadInfo thread_infoMAX_THREAD_NUM ;readcount = 0 ; / 初始化readcounttRP_Write

29、 = CreateMutex(NULL, FALSE, NULL); / 初始化用于讀-寫互斥、寫-寫互斥的信號量ifstream inFile; / 打開文件inFile.open(file) ;printf("Reader Priority:nn") ;while(inFile) /讀人每一個讀者、寫者的信息inFile>>thread_infon_thread.serial ;inFile>>thread_infon_thread.entity;inFile>>thread_infon_thread.delay;inFile>

30、>thread_infon_thread+.persist;inFile.get();for(i = 0; i < (int)(n_thread); i+) if(thread_infoi.entity = READER | thread_infoi.entity = 'r') / 創(chuàng)建讀者線程 h_Threadi = (HANDLE)_beginthreadex(NULL, 0, RP_ReaderThread, &thread_infoi, 0, &thread_ID); else / 創(chuàng)建寫者線程 h_Threadi = (HANDLE)_be

31、ginthreadex(NULL, 0, RP_WriterThread, &thread_infoi, 0, &thread_ID); /等待所有線程結(jié)束wait_for_all = WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1) ;printf("All reader and writer have finished operating.n");/關(guān)閉線程句柄,關(guān)閉信號量句柄for(i = 0; i < (int)(n_thread); i+) CloseHandle(h_Threadi); Cl

32、oseHandle(h_Mutex);CloseHandle(RP_Write);/主函數(shù)int main(int argc, char* argv)char ch;while ( true ) printf("*n");printf(" 1: Reader Priorityn") ;printf(" 2: Exit to Windowsn") ;printf("*n");printf( "Enter your choice (1 or 2): ");/如果輸入信息不正確,繼續(xù)輸入doch =

33、(char)_getch() ; while(ch != '1' && ch != '2'); system("cls") ; /清除控制臺顯示的信息 /選擇2,返回 if(ch = '2')return 0; /選擇l,讀者優(yōu)先 else ReaderPriority("thread.dat"); /結(jié)束 printf("nPress Any Key To Continue:"); _getch() ; system("cls") ;return 0

34、;步驟3:編譯并建立3-2.exe可執(zhí)行文件。在工具欄單擊“Execute Program”按鈕,執(zhí)行3-2.exe程序。(1) 對運行的結(jié)果逐行給出分析描述。_(2) 根據(jù)運行輸出結(jié)果,對照分析3-2程序,畫出程序運行的流程圖(3) 自己定義一組實驗數(shù)據(jù)并保存到文件后再執(zhí)行程序(文件名字為thread.dat, 必須放在相同目錄下,使用記事本按數(shù)據(jù)格式要求編輯),分析執(zhí)行結(jié)果,并觀察結(jié)果是否與設(shè)想的一致。下面是一個測試數(shù)據(jù)文件的例子,僅供參考,實驗是自己定義相關(guān)數(shù)據(jù): 1 R 3 52 W 4 53 R 5 24 R 6 55 W 5.1 33. 選做部分:編程實現(xiàn)生產(chǎn)者消費者問題參照3-2

35、程序,寫出實現(xiàn)單個生產(chǎn)者消費者問題的算法,可以使用單個緩沖區(qū),也可以使用緩沖池,生產(chǎn)者隨機產(chǎn)生任意形式的數(shù)據(jù)并放入緩沖區(qū)中,消費者則以隨機的時間間隔從緩沖區(qū)中取數(shù)據(jù),隨機時間請使用隨機數(shù)產(chǎn)生。首先創(chuàng)建一個生產(chǎn)者線程和一個消費者線程,然后生產(chǎn)者與消費者都以各自的速度生產(chǎn)和消費,而緩沖區(qū)則是兩者的臨界資源。實驗報告內(nèi)容包括:(1)設(shè)計思路的說明;(2)需要幾個同步信號量;(3)解決方法的整體流程;(4)含有詳細注釋的源代碼;(5)測試結(jié)果及分析。幾個API函數(shù)說明1CreateThread 函數(shù)功能:該函數(shù)創(chuàng)建一個在調(diào)用進程的地址空間中執(zhí)行的線程。函數(shù)原型:HANDLE CreateThread

36、(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStacksize, LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter, DWORD dwCreatiOnFlags, LPDWORD lpThreadId);參數(shù)說明:l lpThreadAttributes:指向一個SECURITY_ATTRIBUTES結(jié)構(gòu),該結(jié)構(gòu)決定了返回的句柄是否可被子進程繼承。若lpThreadAttributes為NULL,則句柄不能被繼承。在Windows NT中該結(jié)構(gòu)的lpSecurityDescr

37、iptor成員定義了新進程的安全性描述符。若lpThreadAttributes為NULL,則線程獲得一個默認的安全性描述符。l dwStackSize:定義原始堆棧提交時的大小(按字節(jié)計)。系統(tǒng)將該值舍人為最近的頁。若該值為0,或小于默認時提交的大小,默認情況是使用與調(diào)用線程同樣的大小。更多的信息,請看ThreadStackSize。l lpStartAddress:指向一個LPTHREAD_START_ROUTINE類型的應(yīng)用定義的函數(shù),該線程執(zhí)行此函數(shù)。該指針還表示遠程進程中線程的起始地址。該函數(shù)必須存在于遠程進程中。l lpParameter:定義一個傳遞給該進程的32位值。l dwC

38、reationFlags:定義控制進程創(chuàng)建的附加標志。若定義了CREATE_SUSPENDED標志,線程創(chuàng)建時處于掛起狀態(tài),并且直到ResumeThread函數(shù)調(diào)用時才能運行。若該值為0,則該線程在創(chuàng)建后立即執(zhí)行。l lpThreadId:指向一個32位值,它接收該線程的標識符。返回值:若函數(shù)調(diào)用成功,返回值為新線程的句柄;若函數(shù)調(diào)用失敗,返回值為NULL。2ExitThread函數(shù)功能:該函數(shù)結(jié)束一個線程。函數(shù)原型:VOID ExitThread(DWORD dwEextCode)參數(shù):dwExitCode定義調(diào)用線程的退出代碼。使用GetExitCodeThread函數(shù)來檢測一個線程的退出

39、代碼。返回值:無。說明:調(diào)用ExitThread函數(shù),是結(jié)束一個線程的較好的方法。調(diào)用該函數(shù)后(或者直接地調(diào)用,或者從一個線程過程返回),當前線程的堆棧取消分配,線程終止。若調(diào)用該函數(shù)時,該線程為進程的最后一個線程,則該線程的進程也被終止。線程對象的狀態(tài)變?yōu)榘l(fā)信號狀態(tài),以釋放所有正在等待該線程終止的其他線程。線程的終止狀態(tài)從STILL_ACTIVATE變?yōu)閐wExitCode參數(shù)的值。線程結(jié)束時不必從操作系統(tǒng)中移去該線程對象。當線程的最后一個句柄關(guān)閉時,該線程對象被刪除。3_beginthreadex函數(shù)功能:如果使用C/C+語言編寫多線程應(yīng)用程序,一定不能使用操作系統(tǒng)提供的CreateThr

40、ead API,而應(yīng)該使用C/C+運行時庫中的_beginthreadex函數(shù)原型:uintptr_t _beginthreadex( void *security, /Pointer to a SECURITY_ATTRIBUTES structureunsigned stack_size,unsigned ( _stdcall *start_address )( void * ),void *arglist,unsigned initflag,/Initial state of new thread (0 for running or CREATE_SUSPENDED for suspen

41、ded); unsigned *thrdaddr );參數(shù):l security:安全屬性的指針,可為NULLl stack_size: 線程棧的大小,0代表系統(tǒng)默認大小l start_address: 線程函數(shù)的運行地址,該線程執(zhí)行此函數(shù)(注:函數(shù)名也是該函數(shù)的運行地址)l arglist:參數(shù)值指針l initflag:線程初始狀態(tài)的值,0代表就緒狀態(tài),CREATE_SUSPENDED代表掛起狀態(tài)l thrdaddr:存放線程ID的變量地址返回值: 若函數(shù)調(diào)用成功,返回值為新線程的句柄;若函數(shù)調(diào)用失敗,返回值為NULL。說明:_beginthreadex函數(shù)與Win32 API 中的Cre

42、ateThread函數(shù)類似,但有如下差異: _beginthreadex 函數(shù)初始化某些 C 運行時庫變量,在線程中若需要使用 C 運行時庫,則需要使用_beginthreadex 函數(shù)創(chuàng)建線程。4Sleep函數(shù)功能:該函數(shù)對于指定的時間間隔掛起當前的執(zhí)行線程。函數(shù)原型:VOID Sleep(DWORD dwMilliseconds)參數(shù):dwMilliseconds:定義掛起執(zhí)行線程的時間,以毫秒(ms)為單位。取值為0時,該線程將余下的時間片交給處于就緒狀態(tài)的同一優(yōu)先級的其他線程。若沒有處于就緒狀態(tài)的同一優(yōu)先級的其他線程,則函數(shù)立即返回,該線程繼續(xù)執(zhí)行。若取值為INFINITE則造成無限延

43、遲。返回值:該函數(shù)沒有返回值。說明:一個線程可以在調(diào)用該函數(shù)時將睡眠時間設(shè)為0ms,以將剩余的時間片交出。5CreateMutex函數(shù)功能:該函數(shù)創(chuàng)建有名或者無名的互斥對象。函數(shù)原型:HANDLE CreateMutex (LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);參數(shù):l lpMutexAttributes:指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針,該結(jié)構(gòu)決定子進程是否能繼承返回句柄。如果lpMutexAttributes為NULL,那么句柄不能被繼承。 在Window

44、s NT中該結(jié)構(gòu)的lpSecurityDescriptor成員指定新互斥對象的安全描述符。如果lpMutexAttributes為NULL,那么互斥對象獲得默認的安全描述符。l bInitialOwner:指定互斥對象的初始所屬身份。如果該值為TRUE,并且調(diào)用者創(chuàng)建互斥對象,那么調(diào)用線程獲得互斥對象。否則,調(diào)用線程不能獲得互斥對象。判斷調(diào)用者是否創(chuàng)建互斥對象請參閱返回值部分。l lpName:指向以NULL結(jié)尾的字符串,該字符串指定了互斥對象名。該名字的長度小于MAX_ PATH且可以包含除反斜線()路徑分隔符以外的任何字符。名字是區(qū)分大小寫的。 如果lpName與已存在的有名互斥對象名相匹

45、配,那么該函數(shù)要求用MUTEX_ALL_ACCESS權(quán)限訪問已存在的對象。在這種情況下,由于參數(shù)bInitialOwner已被創(chuàng)建進程所設(shè)置,該參數(shù)被忽略。如果參數(shù)lpMutexAttributes不為NULL,它決定句柄是否解除繼承,但是其安全描述符成員被忽略。 如果lpName為NULL,那么創(chuàng)建的互斥對象無名。 如果lpName與已存在的事件、信號量、可等待定時器、作業(yè)或者文件映射對象的名字相匹配,那么函數(shù)調(diào)用失敗,并且GetLastError函數(shù)返回ERROR_INVALID_HANDLE,其原因是這些對象共享相同的名字空間。返回值: 如果函數(shù)調(diào)用成功,返回值是互斥對象句柄;如果函數(shù)調(diào)

46、用之前,有名互斥對象已存在,那么函數(shù)給已存在的對象返回一個句柄,并且函數(shù)GetLastError返回ERROR_ALREADY_EXISTS,否則,調(diào)用者創(chuàng)建互斥對象。 如果函數(shù)調(diào)用失敗,則返回值為NULL。若想獲得更多錯誤信息,請調(diào)用GetLastError函數(shù)。說明: 由函數(shù)CreateMutex返回的句柄有MUTEX_ALL_ACCESS權(quán)限可以去訪問新的互斥對象,并且可用在請求互斥對象句柄的任何函數(shù)中。 當一個互斥對象不被任何線程擁有時,處于信號態(tài)。創(chuàng)建該對象的線程可以使用bInitialOwner標志來請求立即獲得對該互斥對象的所有權(quán)。否則,線程必須使用等待函數(shù)【例如WaitForS

47、ingleObject函數(shù)】來請求所有權(quán)。當互斥對象處于信號態(tài),等待的線程獲得對該對象的所有權(quán)時,此互斥對象的狀態(tài)被設(shè)置為非信號態(tài),等待函數(shù)返回。任意時刻,僅有一個線程能擁有該互斥對象,線程可以使用ReleaseMutex函數(shù)來釋放對這個互斥對象的所有權(quán)。 若線程已經(jīng)擁有了一個互斥對象,那么它可以重復(fù)調(diào)用等待函數(shù)而不會發(fā)生阻塞,一般情況下,用戶不會重復(fù)等待同一個互斥對象,這種機制防止了線程因等待它已經(jīng)擁有的互斥對象而發(fā)生死鎖。然而,線程必須為每一次等待調(diào)用一次ReleaseMutex函數(shù)來釋放該互斥對象。 兩個或多個進程可以調(diào)用CreateMutex來創(chuàng)建同名的互斥對象,第一個進程實際創(chuàng)建互斥

48、對象,以后的進程打開已存在的互斥對象的句柄。這使得多個進程可以得到同一個互斥對象的句柄,從而減輕了用戶的負擔,使用戶不必判斷創(chuàng)建進程是否為第一個啟動的進程。使用這種技術(shù)時,應(yīng)該把bInitialOwner標志設(shè)為FALSE;否則很難確定開始時哪一個進程擁有該互斥對象。 由于多進程能夠擁有相同互斥對象的句柄,通過使用這個對象,可使多進程同步。以下為共享對象機制: ® 如果CreateMutex中的lpMutexAttributes參數(shù)允許繼承,由CreateProcess函數(shù)創(chuàng)建的子進程可以繼承父進程的互斥對象句柄。 ® 一個進程可以在調(diào)用DuplicateHandle函數(shù)時

49、指定互斥對象句柄來創(chuàng)建一個可以被其他進程使用的雙重句柄。一個進程在調(diào)用OpenMutex或CreateMutex函數(shù)時能指定互斥對象名。 ® 使用CloseHandle函數(shù)關(guān)閉句柄,進程結(jié)束時系統(tǒng)自動關(guān)閉句柄。當最后一個句柄被關(guān)閉時,互斥對象被銷毀。6ReleaseMutex函數(shù)功能:該函數(shù)放棄指定互斥對象的所有權(quán)。函數(shù)原型:BOOL ReleaseMutex(HANDLE hMutex)參數(shù):hMutex:互斥對象句柄。為CreateMutex或OpenMutex函數(shù)的返回值。返回值:如果函數(shù)調(diào)用成功,那么返回值是非零值;如果函數(shù)調(diào)用失敗,那么返回值是零值。若想獲得更多錯誤信息,請調(diào)用GetLastError函數(shù)。說明:如果調(diào)用線程不擁有互斥對象,ReleaseMutex函數(shù)失敗。一個線程通過調(diào)用等待函數(shù)擁有互斥對象。創(chuàng)建該互斥對象的線程也擁有互斥對象,而不需要調(diào)用等待函數(shù)。當互斥對象的所有者線程不再需要互斥對象時,它可以調(diào)用ReleaseMutex函數(shù)。當一個線程擁有一個互斥對象后,它可以用該互斥對象多次調(diào)用等待函數(shù)而不會阻塞。這防止一個線程等待一個它已擁有的互斥對象時出現(xiàn)死鎖。不過,為了釋放所有權(quán),該線程必須為每一個等待操作調(diào)用一次ReleaseMutex函數(shù)。7WaitForSingleObject函數(shù)功能:當下列情況之一發(fā)生時該函數(shù)返回:(1)指定對象處于

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論