操作系統(tǒng)原理 實驗4、5 并發(fā)與調度、存儲管理_第1頁
操作系統(tǒng)原理 實驗4、5 并發(fā)與調度、存儲管理_第2頁
操作系統(tǒng)原理 實驗4、5 并發(fā)與調度、存儲管理_第3頁
操作系統(tǒng)原理 實驗4、5 并發(fā)與調度、存儲管理_第4頁
操作系統(tǒng)原理 實驗4、5 并發(fā)與調度、存儲管理_第5頁
已閱讀5頁,還剩63頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

實驗4

并發(fā)與調度

4.1WindowsXP線程同步

4.1.1WindowsXP的線程同步

WindowsXP提供的常用對象可分成3類:核心應用服務、線程同步和線程間通

訊。其中,開發(fā)人員可以使用線程同步對象來協(xié)調線程和進程的工作,以使其共享

信息并執(zhí)行任務。此類對象包括互鎖數(shù)據(jù)、臨界段、事件、互斥體和信號等。

多線程編程中關鍵的一步是保護所有的共享資源,工具主要有互鎖函數(shù)、臨界

段和互斥體等:另一個實質性部分是協(xié)調線程使其完成應用程序的任務,為此,可

利用內核中的事件對象和信號。

在進程內或進程間實現(xiàn)線程同步的最方便的方法是使用事件對象,這一組內核

對象允許一個線程對其受信狀態(tài)進行直接控制(見表4.1)。

而互斥體則是另一個可命名且安全的內核對象,其主要目的是引導對共享資源

的訪問。擁有單一訪問資源的線程創(chuàng)建互斥體,所有想要訪問該資源的線程應該在

實際執(zhí)行操作之前獲得互斥體,而在訪問結束時立即釋放互斥體,以允許下一個等

待線程獲得互斥體,然后接著進行下去。

與事件對象類似,互斥體容易創(chuàng)建、打開、使用并清除。利用CreateMulex。API

可創(chuàng)建互斥體,創(chuàng)建時還可以指定一個初始的擁有權標志,通過使用這個標志,只

有當線程完成了資源的所有的初始化工作時,才允許創(chuàng)建線程釋放互斥體。

86操作系統(tǒng)原理實驗(第二版)

表4.1用于管理事件對象的API

API名稱描述

在內核中創(chuàng)建一個新的事件對象。此函數(shù)允許有安全性設置、手工還是

CreateEvent()

自動丞置的標志以及初始時已接受還是未接受信號狀態(tài)的標志

創(chuàng)建對己經(jīng)存在的事件對象的引用。此API函數(shù)需要名稱、繼承標志和

OpenEventO

所需的訪問級別

SctEvcntO將手工重置事件轉化為已接受信號狀態(tài)

ResetEvent()將手工重置事件轉化為非接受信號狀態(tài)

將自動重置事件對象轉化為已接受信號狀態(tài)。當系統(tǒng)釋放所有的等待它

PulseEventO

的線程時此種轉化立即發(fā)生

為了獲得互斥體,首先,想要訪問調用的線程可使用OpenMutexOAPI來獲得指

向對象的句柄;然后,線程將這個句柄提供給一個等待函數(shù)。當內核將互斥體對象

發(fā)送給等待線程時,就表明該線程獲得了互斥體的擁有權。當線程獲得擁有權時,

線程控制了對共享資源的訪問一一必須設法盡快地放棄互斥體。放棄共享資源時需

要在該對象上調用RcleaseMutcOAPI。然后系統(tǒng)負責將互斥體擁有權傳遞給下?個等

待著的線程(由到達時間決定順序)。

4.1.2練習與實驗

在本實驗中,通過對尋件和互斥體對象的了解,來加深對WindowsXP線程同步

的理解。

1)回顧系統(tǒng)進程、線程的有關概念,加深對WindowsXP線程的理解。

2)了解事件和互斥體對象。

3)逋過分析實驗程序,了解管埋事件對象的APE

4)了解在進程中如何使用事件對象。

5)了解在進程中如何使用互斥體對象。

6)了解父進程創(chuàng)建子進程的程序設計方法。

1.工具/準備工作

在開始本實驗之前,請回顧教科書的相關內容。

需要準備一臺運行WindowsXPProfessional操作系統(tǒng)的計算機,且該計算機中

需安裝VisualC++6.0專業(yè)版或企業(yè)版。

2.實驗內容與步驟

(1)事件對象

清單4-1程序展示了如何在進程間使用事件。父進程啟動時,利用CreateEvenK)

API創(chuàng)建一個命名的、可共享的事件和子進程,然后等待子進程向事件發(fā)出信號并終

止父進程。在創(chuàng)建時,子進程通過OpcnEvent。API打開事件對象,調用SctEvcnt()API

使其轉化為已接受信號狀態(tài)。兩個進程在發(fā)出信號之后幾乎立即終止。

步驟1:登錄進入WindowsXPProfessionalo

步驟2:在“開始”菜單中單擊MicrosoftVisualC++6.0命令,進入VisualC++

窗口。

步驟3:編輯實驗源程序4-1.cpp(也可直接打開下載的源程序文件4-1.cpp)。

清單47創(chuàng)建和打開事件對象在進程間傳送信號

//event項目

#include<windows.h>

#include<iostream>

//以下是句柄事件。實際中很可能使用共享的包含文件來進行通訊

staticLPCTSTRg_szContinueEvent="w2kdg.EventDemo.event.Continue":

//本方法只是創(chuàng)建了一個進程的副本,以子進程模式(由命令行指定)工作

BOOLCreateChildO

(

//提取當前可執(zhí)行文件的文件名

TCHARszFilename[MAX_PATH];

::GetModuleFileName(NULL,szFilename,MAXPATH);

//格式化用于子進程的命令行,指明它是一個EXE文件和子進程

TCHARszCmdLine[MAX_PATH];

::sprintf(szCmdLine,為szFilename);

//子進程的啟動信息結構

STARTUPINFOsi;

::ZeroMemory(reinterpret_cast<void*>(&si),sizeof(si));

si.cb=sizeof(si);//必須是本結構的大小

88操作系統(tǒng)原理實驗(第二版)

//返回的子進程¥J進程信息結構

PROCESS.INFORMATIONpi;

//使用同一可執(zhí)行文件和告訴它是一個子進程的命令行創(chuàng)建進程

BOOLbCreateOK=::CreateProcess(

szFilenamG,//生成的可執(zhí)行文件名

szCmdLine,//指示其行為與子進程一樣的標志

NULL,//子進程句柄的安全性

NULL,//子線程句柄的安全性

FALSE,//不繼承句柄

o,//特殊的創(chuàng)建標志

NULL,//新環(huán)境

NULL,//當前目錄

&si,//啟動信息結構

&pi);//返回的進程信息結構

//釋放對子進程的引用

if(bCreateOK)

(

::CloseHandle(pi.hProcess);

::CloseHandle(pi.hThread);

)

return(bCreateOK);

}

//下面的方法創(chuàng)建一個事件和?個子進程,然后等待子進程在返回前向事件發(fā)出信號

voidWaitForChild()

(

//createaneweventobjectfortheshildprocess

//tousewhenreleasingthisprocess

HANDLEhEvantOcntinu良=::CrAatAEvAnh(

NULL,//缺省的安全性,子進程將具有訪問權限

TRUE,//手工重置事件

FALSE,//初始時是非接受信號狀態(tài)

g_szContir.ueEvent);//事件名稱

if(hEventContinue!=NULL)

(

std::cout<<"eventcreated*'<<std::endl;

//創(chuàng)建子進程

if(::CreateChild())

(

std::cout<<"childcreated"<<std::endl;

//等待,直到子進程發(fā)出信號

std::cout?nParentwaitingonchild.n?stci::endl;

::WaitForSingleObject(hEventContinue,INFINITE);

::Sleep(1500);//刪去這句試試

std::cout<<Mparentreceivedtheenventsignalingfrom

childn<<std::endl;

}

//清除句柄

::CloseHardle(hEventContinue);

hEventContinue=INVALID_HANDLE_VALUE;

)

)

//以下方法在子進程模式下被調用,其功能只是向父進程發(fā)出終止信號

voidSignalparent()

(

//嘗試打開句柄

std::cout<<nchildprocessbeginningu?std::endl;

HANDLEhEventOontinue=::OpenEvent(

EVENT_MODIFY_STATE,//所要求的最小訪問權限

FALSE,//不是可繼承的句柄

g_szContirueEvent);//事件名稱

if(hEventContinue!=NULL)

90操作系統(tǒng)原理實驗(第二版)

(

::SetEvent(hEventContinue);

std::cout<<'*eventsignaled"<<std::endl;

}

//清除句柄

::CloseHandle(hEventContinue);

hEventContinue=INVALID_HANDLE_VALUE;

}

intmain(intargc,char*argv(])

(

//檢查父進程或是子進程是否啟動

if(argc>l&&::strcmp(argv[l],Mchild")==0)

(

//向父進程創(chuàng)建的事件發(fā)出信號

::SignalParent();

}

else

(

//創(chuàng)建一個事件并等待子進程發(fā)出信號

::WaitForChild();

::Sleep(1500);

std::cout<<"Parentreleased."<<std::endi;

}

return0;

)

步驟4:單擊Build菜單中的Compile4-l.cpp命令,并單擊“是”按鈕確認。系

統(tǒng)對4-1.cpp進行編譯。

步驟5:編譯完成后,單擊Build菜單中的Build4-l.exe命令,建立4-l.exe可執(zhí)

行文件。

操作能否正常進行?如果不行,則可能的原因是什么?

步驟6:在工具欄單擊ExecuteProgram(執(zhí)行程序)按鈕,執(zhí)行4-l.exe程序。

請記錄:運行結果(分行書寫。如果運行不成功,則可能的原因是什么?):

1)_____________________________________________________________________

2)____________________________________________________________________

3)____________________________________________________________________

4)____________________________________________________________________

5)____________________________________________________________________

6)____________________________________________________________________

請從進程并發(fā)的角度對結果進行分析,這個結果與你期望的一致嗎?

閱讀和分析程序4-1,請回答:

1)程序中,創(chuàng)建一個事件使用了哪一個系統(tǒng)函數(shù)?創(chuàng)建時設置的初始信號狀態(tài)

是什么?

a.____________________________________________________________________

b.____________________________________________________________________

2)創(chuàng)建一個進程(子進程)使用了哪一個系統(tǒng)函數(shù)?

3)從步驟6的輸出結果,對照分析4-1程序,可以看出程序運行的流程嗎?請

簡單描述:

4)這是一個簡單的進程同步的例子。請簡述進程同步在這個程序中是如何實現(xiàn)

的。

(2)互斥體對象

清單4-2的程序中顯示的類CCountUpDown使用了一個互斥體來保證對兩個線

程間單一數(shù)值的訪問。每個線程都企圖獲得控制權來改變該數(shù)值,然后將該數(shù)值寫

入輸出流中。創(chuàng)建者實際上創(chuàng)建的是互斥體對象,計數(shù)方法執(zhí)行等待并釋放,為的

是共同使用互斥體所需的資源(因而也就是共享資源)。

步驟1:編輯實驗源程序4-2.cpp(也可直接打開下載的源程序文件4-2.cpp)o

92操作系統(tǒng)原理實驗(第二版)

清單4-2利用互斥體保護共享資源

//mutex項目

#include<windows.h>

#include<iostream>

//利用互斥體來保護司時訪問的共享資源

classCCountUpDown

(

public:

//創(chuàng)建者創(chuàng)建兩個線程來訪問共享值

CCountUpDown(intnAccesses):

m_hThreadInc(INVALID_HANDLE_VALUE),

m_hThreadDec(INVALID_HANDLE_VALUE),

m_hMutexValue(INVALID_HANDLE_VALUE),

mnValue(C),

m_nAccess(nAccesses)

(

//創(chuàng)電互斥體用于訪問數(shù)值

m_hMutexValue=::CreateMutex(

NULL,//缺省的安全性

TRUE,//初始時擁有,在所有的初始化結束時將釋放

NULL);//匿名的

m_hThreadInc=::CreateThread(

NULL,//缺省的安全性

0,//缺省堆棧

IncThreadProc.//類線程進程

reinterpret_cast<LPVOID>(this),//線程參數(shù)

0,//無特殊的標志

NULL);//忽略返回的id

m_hThreadDec=::CreateThread(

NULL,//缺省的安全性

0,//缺省堆棧

DecThreadProc,//類線程進程

reinterpret_cast<LPVOID>(this)r//線程參數(shù)

0z//無特殊的標志

NULL);//忽略返回的id

//允許另一線程獲得互斥體

::ReleaseMutex(m_hMutexValue);

}

//解除程序釋放對對象的引用

virtual~CCountUpDown()

(

::CloseHardle(m_hThreadInc);

::CloseHardle(m_hThreadDec);

::CloseHardle(m_hMutexValue);

}

//簡單的等待方法,在兩個線程終止之前可暫停主調者

virtualvoidWaitForCompletion()

(

//確保所有對象都已準備好

if(m_hThreadInc!=INVALID_HANDLE_VALUE&&

m_hThreadDec!=INVALID_HANDLE_VALUE)

(

//等待兩者完成(順序并不重要)

::WaitForSingleObject(m_hThreadInczINFINITE);

::WaitForSingleObject(m_hThreadDeczINFINITE);

)

}

protected:

//改變共享資源妁簡單的方法

virtualvoidDoCount(intnStep)

(

//循環(huán),直到所有的訪問都結束為止

while(1)

(

//等待訪問數(shù)值

::WaitForSingleObject(m_hMutexValue,INFINITE);

94操作系統(tǒng)原理實驗(第二版)

if(m_nAccess>0)(

//改變并顯示該值

m_nValue+=nStep;

std::cout?''thread:"<<■::GetCurrentThreadld()

〈〈''value:z,?m_nvalue?''access:,z<<m_nAccess

:rendl;

//發(fā)出訪問信號并允許線程切換

——m_nAccess;

::Sleep(1000);//實現(xiàn)線程切換,并使顯示速度放慢

//釋放對數(shù)值的訪問

::ReleaseMutex(mhMutexValue);

)

elsebreak;

}

)

staticDWORDWINAPIIncThreadProc(LPVOIDIpParam)

(

//將參數(shù)解釋為"this,指針

CCountUpDc-wn*pThis=

reinterpret_cast<CCountUpDown*>(ipParam);

//調用對象的增加方法并返回一個值

pThis->DoCount(+1);

return(0);

}

staticDWORDWINAPIDecThreadProc(LPVOIDIpParam)

(

//將參數(shù)解釋為'this,指針

CCountUpDown*pThis=

reinterpretcast<CCountUpDown*>(IpParam);

//調用對象的減少方法并返回?個值

pThis->DOCount(-1);

return(0);

}

protected:

HANDLEm_hThreadInc;

HANDLEm_hThreadDec;

HANDLEm_hMutexValue;

intm_nValue;

intm_nAccess;

};

voidmain()

(

CCountUpDownud(50);

ud.WaitForCompletion();

)

步驟2:單擊Build菜單中的Compile42cpp命令,并單擊“是”按鈕確認。系

統(tǒng)對4-2.cpp進行編譯。

步驟3:編譯完成后,單擊Build菜單中的Build4-2.exe命令,建立4-2.exe可執(zhí)

行文件。

請記錄:操作能否正常進行?如果不行,則可能的原因是什么?

步驟4:在工具欄單擊ExecuteProgram按鈕,執(zhí)行4-2.exe程序。

分析程序4-2的運行結果,可以看到線程(加和減線程)的交替執(zhí)行(因為Sleep。

API允許Windows切換線程)。在每次運行之后,數(shù)值應該返回初始值(0),因為

在每次運行至sleep。語句后,寫入線程在等待隊列中變成最后一個,內核保證它在

其他線程工作時不會再運行,力口、減線程各自運行了25次。

I)請描述運行結果(如果運行不成功,則可能的原因是什么?):

96操作系統(tǒng)原理實驗(第二版)

2)根據(jù)運行輸出結果,對照分析4-2程序,可以看出程序運行的流程嗎?請簡

單描述加、減線程是如何交替執(zhí)行的?

3)程序4-2中臨界資源、臨界區(qū)各是什么?是加何實現(xiàn)線程對臨界資源的互斥

訪問的?

3.實驗總結

4.實驗評價(教師)

4.1.3閱讀與思考

4.2WindowsXP線程間的通訊

WindowsXP提供的線程間通訊類內核對象允許同一進程或跨進程的線程之間互

相發(fā)送信息,包括文件、文件映射、郵件位和命名管道等,其中最常用的是文件和

文件映射。這類對象允許一個線程很容易地向同一進程或其他進程中的另一線程發(fā)

送信息。

4.2.1文件對象

文件對象是人們所熟悉的永久存儲的傳統(tǒng)元素。將一個文件看作是內核對象可

使開發(fā)人員獲得比標準C++文件操作更為強大的功能,

內核允許開發(fā)人員在系統(tǒng)設備或網(wǎng)絡上創(chuàng)建代表永久存儲數(shù)據(jù)塊的文件對象。

這些文件對象是對永久存儲數(shù)據(jù)的低級訪問者;用C++運行庫或其他方法打開的所

有文件最終都要變成對CreateFile()API的調用。

CreateFile()函數(shù)分配一個內核對象來代表一個永久的文件。當在磁盤上創(chuàng)建一

個新文件或當打開一個已經(jīng)存在的文件時,就調用這個API,其參數(shù)總結見表4.2。

表4.2CreateFiie()API的參數(shù)

參數(shù)名使用目的

LPCTSTRIpFilcName要打開或創(chuàng)建的文件名

所要求的文件訪問權;一個包括GENERIC_READ或

DWORDdwDesiredAccess

GENERIC.WRITE的屏蔽

DWORDdwShareMode指定與其他進程共享的文件類型(如果有的話)

LPSECURITY_ATTRIBUTES

當被文件系統(tǒng)支持時與備份文件對象有關的安全性

IpSccurityAitributcs

在文件系統(tǒng)的級別上所采取的操作的類型。如新文件的創(chuàng)建

DWORDdwCrealionDisposilion

或打開一個已有的文件

文件系統(tǒng)的屬性,如只讀、隱藏等。還可以是文件對象的屬

DWORDdwFlagsAndAuribiiles

性,如可緩存寫入等

HANDLEhTemplateFile指向另一文件對象的句柄,常用于為新創(chuàng)建的文件提供屬性

創(chuàng)建調用比創(chuàng)建事件、互斥體或信號量要復雜。首先必須在IpFilename中指定

對象名,并且要指向文件系統(tǒng)中所訪問的位置。接著必須用dwDesiredAccess參數(shù)提

供所需的訪問級別。

山創(chuàng)建函數(shù)要求的共享模式參數(shù)dwShareMode可以指定當另一進程企圖同時訪

問數(shù)據(jù)時會發(fā)生什么。與所有其他第一級內核對象一樣,可以利用1pSecurityAttributes

參數(shù)指定所創(chuàng)建對象的安全性。接著,要通過dwCrealionDisposilion參數(shù)告訴創(chuàng)建函

數(shù),加果數(shù)據(jù)在指定的永久存儲介質中存在或不存在時的行為。

可以使用dwFlagsAndAllribules參數(shù)來指定文件的屬性(如只讀),并確定對數(shù)

據(jù)所執(zhí)行的讀寫操作的行為。最后一個參數(shù)hTemplateFile可指定另一個文件對象作

98操作系統(tǒng)原理實驗(第二版)

為模板,以便為新創(chuàng)建的文件復制屬性或擴展屬性。

WindowsXP系統(tǒng)中包括許多文件對象的工具函數(shù),表4.3中總結了處理文件對

象時需要使用的API。

表4.3文件對象API

API名稱功能描述

創(chuàng)建文件內核對象,用于代表文件系統(tǒng)中新的或已經(jīng)存在的大

CreateFile()

量數(shù)據(jù)

從文件系統(tǒng)中的由文件對象句柄引用的文件發(fā)送數(shù)據(jù)。讀操作

ReadFileO

開始于當前文件的指針位置,每讀取一個字節(jié),該位置增加

從文件系統(tǒng)中的由文件對象句柄引用的文件發(fā)送數(shù)據(jù)。寫操作

WriteFileO

開始于當前文件的指針位置,每寫入一個字節(jié),該位置增加

SetFilePointer()將文件中的當前文件指針位置移動一個相對或絕對距離

SetEndOfFileO將文件的終止記號移動到當前文件指針的位置

LockFileO防止其他進程訪問傳遞的文件內的一個區(qū)域

GetFileType()決定傳遞的句柄是否引用磁盤文件、控制臺或命名的管道

GetFileSizeEx()提取64位的文件容量

GetFileTimeO提取文件創(chuàng)建、最后訪問和最近修改的時間

用傳遞來的文件中的詳細信息填充BY_HANDLE_FILE_

GetFilelnformationByHandleO

INFORMATION數(shù)據(jù)結構

通??梢允褂肦eadFile。和WrileFile。API在永久存儲和應用程序間通過文件對

象來移動數(shù)據(jù)。因為創(chuàng)建調用將對象的大多數(shù)復雜性封裝起來了,這兩個函數(shù)只是

簡單地利用指向要交換數(shù)據(jù)的文件對象的句柄(即指向內存內的數(shù)據(jù)緩存區(qū)的指

針),然后計數(shù)移動數(shù)據(jù)的字節(jié)數(shù)。除此之外,這兩個函數(shù)還執(zhí)行重疊式的輸入和輸

出,由于不會“堵塞”主線程,可用來傳送大量的數(shù)據(jù)。

CreateFile。方法除了可訪問標準的永久文件外,還可訪問控制臺輸入和輸出,

以及從命名的管道來的數(shù)據(jù)。

GelFileType()API指明要處理的關鍵文件句柄的結構。除此之外,內核還提供了

GetFileInformationByHandle()和GetFileSize。>GetFileTime()API用于獲得關鍵數(shù)據(jù)

的詳細情況。其他用于在文件中改變數(shù)據(jù)的工具函數(shù)包括LockFileO.SetFilePointerO

和SetEndOfFileOAPL

除了這些基于句柄的API之外,內核還提供了大量的工具,用于按文件名對文

件直接操作。文件對象用完之后,應該用CloseHandle()API加以清除。

4.2.2文件映射對象

比使用RcadFile。和WritcFilc。API通過文件對象來讀取和寫入數(shù)據(jù)更為簡單的

是,WindowsXP還提供了一種在文件中處理數(shù)據(jù)的方法,名為內存映射文件,也稱

為文件映射。文件映射對象是在虛擬內存中分配的永久或臨時文件對象區(qū)域(如果可

能的話,可大到整個文件),可將其看作是二進制的數(shù)據(jù)塊。使用這類對象,可獲得

直接在內存中訪問文件內容的能力。

文件映射對象提供了強大的掃描文件中數(shù)據(jù)的能力,而不必移動文件指針。對

于多線程的讀寫操作來說,這一點特別有用,因為每個線程都可能想要把讀取指針

移動到不同的位置去一一為了防止這種情況,就需要使用某種線程同步機制保護文

件。

在CreateFileMapping()API中,一個新的文件映射對象需要有一個永久的文件對

象(由CreateFileO所創(chuàng)建)。該函數(shù)使用標準的安全性和命名參數(shù),還有用于允許

操作(如只讀)的保護標忐以及映射的最大容量。隨后可根據(jù)來自OpenFileM叩ping()

API的其他線程或進程使用該映射一一這與事件和互斥體的打開進程是非常類似的。

內存映射文件對象的另一個強大的應用是可請求系統(tǒng)創(chuàng)建一個運行映射的臨時

文件。該臨時文件提供一個臨時的區(qū)域,用于線程或進程互相發(fā)送大量數(shù)據(jù),而不

必創(chuàng)建或保護磁盤上的文件。利用向創(chuàng)建函數(shù)中發(fā)送INVAL1D_HANDLE_VALUE

來代替真正的文件句柄,就可創(chuàng)建這一臨時的內存映射文件;指令內核使用系統(tǒng)天

式文件來建立支持映射的最大容量的臨時數(shù)據(jù)區(qū)。

為了利用文件映射對象,進程必須將對文件的查看映射到它的內存空間中。也

就是說,應該將文件映射對象想象為進程的第一步,在這一步中,當查看實際上允

許訪問的數(shù)據(jù)時,附加有共享數(shù)據(jù)的安全性和命名方式.為了獲得指向內存區(qū)域的

指針需要調用MapViewOfFileOAPI,此調用使用文件映射對象的句柄作為其主要參

數(shù)。此外還有所需的訪問等級(如讀-寫)和開始查看時文件內的偏移和要查看的容

量。該函數(shù)返回一-個指向進程內的內存的指針,此指針可有多種編程方面的應用(但

不能超過訪問權限)。

當結束文件映射查看時,必須用接受到的指針調用UnmapVicwOfFlic()AP【,然

后再根據(jù)映射對象調用CloseHandleOAPL從而將其清除。

4.2.3練習與實驗

在本實驗中,通過對乂件和文件映射對象的了解,來加深對WindowsXP線程同

I(X)操作系統(tǒng)原理實驗(第二版)

步的理解。

1)回顧系統(tǒng)進程、線程的有關概念,加深對WindowsXP線程間通訊的理解;

2)了解文件和文件映射對象;

3)通過分析實驗程序,了解線程如何通過文件對象發(fā)送數(shù)據(jù);

4)了解在進程中如何使用文件對象;

5)通過分析實驗程序,了解線程如何通過文件映射對象發(fā)送數(shù)據(jù);

6)了解在進程中如何使用文件映射對象.

1.工具/準備工作

在開始本實驗之前,請回顧教科書的相關內容。

需要準備一臺運行WindowsXPProfessional操作系統(tǒng)的計算機,且該計算機中

需安裝VisualC++6.0專業(yè)版或企業(yè)版。

2.實驗內容

(1)文件對象

清單4-3中的代碼展示了線程如何通過文件對象在永久存儲介質上互相發(fā)送數(shù)

據(jù)。程序只是激活并啟動了一個線程接著一個線程的創(chuàng)建線程。每個線程從指定的

文件中讀取數(shù)據(jù),并對數(shù)據(jù)進行修改,其修改增量是以創(chuàng)建時發(fā)送給它的數(shù)量進行

的,然后將新數(shù)值寫回文件。

步驟1:登錄進入WindowsXPProfessional?

步驟2;在“開始”菜單中單擊MicrosoftVisualC++6.0命令,進入VisualC++

窗口。

步驟3:編輯實險源程序43cpp(也可直接打開下載的源程序文件4-3.叩p)。

清單4-3演示線程通過文件對象發(fā)送數(shù)據(jù)

//fileobj項目

#include<windows.h>

#include<iostream>

//要使用的文件名

staticLPCTSTRg_szFileName=''w2kdg.Fileobj.file.data.txtz,;

//在數(shù)據(jù)文件中讀取當前數(shù)據(jù)的簡單線程時將傳遞來的該數(shù)據(jù)增加,并寫回數(shù)據(jù)文件中

staticDWORDWINAPIThreadProc(LPVOIDIpParam)

//將參數(shù)翻譯為長整數(shù)

LONGnAdd=reinterpret_cast<LONG>(IpParam);

//建立完全的指定文件名(包括路徑信息)

TCHARszFullName[MAX_PATH];

::GetTempPath(MAX_PATH,szFullName);//取得路徑

::strcat(szFullName,g_szFileName);

//打開文件對象

HANDLEhFile=::CreateFile(

szFullName,//文件的完全名稱

GENERIC_READ|GENERIC_WRITEZ//具有所有的訪問權

FILE_SHARE_READZ//允許其他線程讀取

NULL,//缺省的安全性

OPEN_ALWAYS,//創(chuàng)建或打開文件

FILE_ATTRIBUTE_NORMAL,//普通文件

NULL);//無模板文件

if(hFile!=INVALID_HANDLE_VALUE)

(

//讀取當前數(shù)據(jù)

LONGnValue(0);

DWORDdwXier(U);

::ReadFile(

hFile,//要讀取的文件

reinterpret_cast<LPVOID>(SnValue),//緩沖區(qū)

sizeof(nValue),//緩沖區(qū)容量

SdwXfer,//讀取的字節(jié)數(shù)

NULL);//無重疊I/O

//顯示當前數(shù)據(jù)

std::cout<<''read:,,<<nValue<<std::endl;

)

102操作系統(tǒng)原理實驗(第二版)

//增加數(shù)值

nValue+=nAdd;

//寫回永久存儲介質

::SetFilePointer(hFile,O,NULL,FILE_BEGIN);

::WriteFile(

hFile,//要寫入的文件

reinterpretcast<LPCVOID>(&nValue),//數(shù)據(jù)

sizeof(nValue),//緩沖區(qū)容量

&dwXferz//寫入的字節(jié)數(shù)

NULL);//無重登I/O

if(dwXfer==sizeof(nValue))

std::cout<<''v;rite:"z?nValue<<std::endl;

}

〃清除文件

::CloseHandle(hFile);

hFile=INVALID_HANDLE_VALUE;

)

return(0);

)

voidmain()

//創(chuàng)建100個線程從文件中進行讀寫

for(intnTotal=100;nTotal>0;-nTotal)

(

//啟動線程

HANDLEhThread=::CreateThread(

NULL,〃缺省的安全性

0,//缺省的堆棧

ThreadProc,//線程函數(shù)

reinterpret_cast<LPVOID>(1)z//增量

0,//無特殊的創(chuàng)建標志

NULL);//忽略線程id

//等待線程完成

::WaitForSingleObject(hThread,INFINITE);

::Sleep(5C0);//放慢顯示速度,方便觀察

//釋放指向線程的句柄

::CloseHar.dle(hThread);

hThread=INVALID_HANDLE_VALUE;

}

}

步驟4:單擊Build菜單中的Compile4-3.cpp命令,并單擊“是”確認。系統(tǒng)對

4-3.cpp進行編譯。

步驟5:編譯完成后,單擊Build菜單中的Build4-3.exe命令,建立4-3.exe可執(zhí)

行文件。

請記錄:操作能否正常進行?如果不行,則可能的原因是什么?

步驟6:在工具欄單擊ExecuteProgram按鈕,執(zhí)行4-3.exe程序。

請記錄:運行結果(如果運行不成功,則可能的原因是什么?):

閱讀和分析程序4-3,請回答問題:

1)清單4-3中啟動了多少個單獨的讀寫線程?

2)使用了哪個系統(tǒng)API函數(shù)來創(chuàng)建線程例程?

3)文件的讀和寫操作分別使用了哪個API函數(shù)?

104操作系統(tǒng)原理實驗(第二版)

每次運行進程時,都可看到清單4-3中的每個線程從前面的線程中讀取數(shù)據(jù)并將

數(shù)據(jù)增加,文件中的數(shù)值連續(xù)增加。這個示例是很簡單的通訊機制。可將這一示仞

用作編寫自己的文件讀/寫代碼的模板。

請注意程序中寫入之前文件指針的重置。重置文件指針是必要的,因為該指針

在讀取結束時將處于前四個字節(jié)之后,同一指針還要用于向文件寫入數(shù)據(jù)。如果函

數(shù)向該處寫入新數(shù)值,則下次進程運行時,只能讀到原來的數(shù)值。那么:

4)在程序中,重置文件指針使用了哪一個函數(shù)?

5)從步驟6的輸出結果,對照分析4-3程序,可以看出程序運行的流程嗎?請

簡單描述:

6)程序main函數(shù)中,語句::WaitForSingleObject(hThread,INFINITE);有何作

用?

(2)文件映射對象

清單4-4的程序展示了一個在線程間使用的由頁式文件支持的文件映射對象,從

中可以看出利用內存映射文件比使用駐留在磁盤上的文件對象更為簡單。其中的正

程還使用了互斥體,以便公平地訪問文件映射對象,然后,當每個線程都釋放時,

程序將文件的視圖映射到文件上并增加數(shù)據(jù)的值。

步驟1:編輯實驗源程序4-4.cpp(也可直接打開下我的源程序文件4-4.cpp)o

清單4-4演示使用映射文件的內存交換數(shù)據(jù)的線程

//mappings項目

#include<windows.h>

#include<iostream>

//仲裁訪問的互斥體

staticHANDLEg_hMutexMapping=INVALID_HANDLE_VALUE;

//增加共享內存中的數(shù)值的簡單線程

staticDWORDWINAPIThreadProc(LPVOIDIpParam)

//將參數(shù)看作句柄

HANDLEhMapping=reinterpret_cast〈HANDLE〉(IpParam);

//等待對文件的訪問

::WaitForSingleObject(g_hMutexMapping,INFINITE);

〃映射視圖

LPVOIDpFile=::MapViewOfFile(

hMapping,//保存文件的對象

FILE_MAP_ALLACCESS,//獲得讀寫權限

0,//在文件的開頭處(高32位)開始

0,//...(低32位)

0);//映射整個文件

if(pFile!=NULL)

(

//將數(shù)據(jù)看作長整數(shù)

LONG*pnData=reinterpret__cast<LCNG*>(pFile);

//改動數(shù)據(jù)

++(*pnData);

//顯示新數(shù)值

std::cout<<''thread:''<<::GetCurrentThreadld()

<<"value:''<<(*pnData)<<std::endl;

//釋放文件視圖

::UnmapViGwOfFile(pFile);

pFile=NULL;

}

//釋放對文件的訪問權

::AasAMut.Ax(g_hMut.AxMapping);

return(0);

|

106操作系統(tǒng)原理實驗(第二版)

//創(chuàng)建共享數(shù)據(jù)空間

HANDLEMakeSharedFile()

//創(chuàng)建文件映射對象

HANDLEhMapping=::CreateFileMapping(

INVALID_HANDLE_VALUE,//使用頁式文件臨時文件

NULL,//缺省的安全性

PAGEREADWRITE,//可讀寫權

Oz//最大容量(高32位)

sizeof(LONG),//...(低32位)

NULL);//匿名的

if(hMapping!=INVALID_HANDLE_VALUE)

//在文件映對上創(chuàng)建視圖

LPVOIDpDsta=::MapViewOfFile(

hMapping,//保存文件的對象

FILE_MAP_ALL_ACCESS,//獲得讀寫權

0,//在文伯的開頭處(高32位)開始

...(低位)

0z//32

0);//映射整個文件

if(pData!=NULL)

::ZeroMemory(pData,sizeot(LONG));

)

//關閉文件視圖

::UnmapViewOfFile(pData);

}

return(hMapping);

}

voidmain()

//創(chuàng)建數(shù)據(jù)文件

HANDLEhMapping=::MakeSharedFile();

//創(chuàng)建仲裁的互斥體

g_hMutexMapping=::CreateMutex(NULL,FALSE,NULL);

//根據(jù)文件創(chuàng)建100個線程來讀寫

for(intnTotal=100;nTotal>0;--nTotal)

(

//啟動線程

HANDLEhThread=::CreateThread(

NULL,//缺省的安全性

0,//缺省堆棧

ThreadProc,//線程函數(shù)

reinterpret_cast<LPVOID>(hMapping),//增量

0,//無特殊的創(chuàng)建標志

NULL);//忽略線程id

//等待最后的線程釋放

if(nTotal==1)

(

std::cout?''allt

溫馨提示

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

評論

0/150

提交評論