第一篇:操作系統(tǒng)課程設(shè)計(jì)報(bào)告——讀者寫者問(wèn)題
操作系統(tǒng)課程設(shè)計(jì)
課
題:讀者寫者問(wèn)題 姓
名:赫前進(jìn) 班
級(jí):1020552 學(xué)
號(hào)102055211 指導(dǎo)教師:葉瑤 提交時(shí)間:2012/12/30
(一)實(shí)驗(yàn)?zāi)康?/p>
1.進(jìn)一步理解 “臨界資源” 的概念;
2.把握在多個(gè)進(jìn)程并發(fā)執(zhí)行過(guò)程中對(duì)臨界資源訪問(wèn)時(shí)的必要約束條件; 3.理解操作系統(tǒng)原理中 “互斥” 和 “同步” 的涵義。
(二)實(shí)驗(yàn)內(nèi)容
利用程序設(shè)計(jì)語(yǔ)言編程,模擬并發(fā)執(zhí)行進(jìn)程的同步與互斥(要求:進(jìn)程數(shù)目不少于 3 個(gè))。
(三)、程序分析
讀者寫者問(wèn)題的定義如下:有一個(gè)許多進(jìn)程共享的數(shù)據(jù)區(qū),這個(gè)數(shù)據(jù)區(qū)可以是一個(gè)文件或者主存的一塊空間;有一些只讀取這個(gè)數(shù)據(jù)區(qū)的進(jìn)程(Reader)和一些只往數(shù)據(jù)區(qū)寫數(shù)據(jù)的進(jìn)程(Writer),此外還需要滿足以下條件:(1)任意多個(gè)讀進(jìn)程可以同時(shí)讀這個(gè)文件;(2)一次只有一個(gè)寫進(jìn)程可以往文件中寫;
(3)如果一個(gè)寫進(jìn)程正在進(jìn)行操作,禁止任何讀進(jìn)程度文件。
實(shí)驗(yàn)要求用信號(hào)量來(lái)實(shí)現(xiàn)讀者寫者問(wèn)題的調(diào)度算法。實(shí)驗(yàn)提供了signal類,該類通過(guò)P()、V()兩個(gè)方法實(shí)現(xiàn)了P、V原語(yǔ)的功能。實(shí)驗(yàn)的任務(wù)是修改Creat_Writer()添加寫者進(jìn)程,Creat_Reader()創(chuàng)建讀者進(jìn)程。Reader_goon()讀者進(jìn)程運(yùn)行函數(shù)。讀優(yōu)先:要求指一個(gè)讀者試圖進(jìn)行讀操作時(shí),如果這時(shí)正有其他讀者在進(jìn)行操作,他可直接開始讀操作,而不需要等待。
讀者優(yōu)先的附加限制:如果一個(gè)讀者申請(qǐng)進(jìn)行讀操作時(shí)已有另一讀者正在進(jìn)行讀操作,則該讀者可直接開始讀操作。
寫優(yōu)先:一個(gè)讀者試圖進(jìn)行讀操作時(shí),如果有其他寫者在等待進(jìn)行寫操作或正在進(jìn)行寫操作,他要等待該寫者完成寫操作后才開始讀操作。
寫者優(yōu)先的附加限制:如果一個(gè)讀者申請(qǐng)進(jìn)行讀操作時(shí)已有另一寫者在等待訪問(wèn)共享資源,則該讀者必須等到?jīng)]有寫者處于等待狀態(tài)后才能開始讀操作。
在Windows 7 環(huán)境下,創(chuàng)建一個(gè)控制臺(tái)進(jìn)程,此進(jìn)程包含 n 個(gè)線程。用這 n 個(gè)線程來(lái)表示 n 個(gè)讀者或?qū)懻摺C總€(gè)線程按相應(yīng)測(cè)試數(shù)據(jù)文件(格式見下)的要求進(jìn)行讀寫操作。用信號(hào)量機(jī)制分別實(shí)現(xiàn)讀者優(yōu)先和寫者優(yōu)先的讀者/寫者問(wèn)題。運(yùn)行結(jié)果顯示要求:要求在每個(gè)線程創(chuàng)建、發(fā)出讀寫操作申請(qǐng)、開始讀寫操作和結(jié)束讀寫操作時(shí)分別顯示一行提示信息,以確定所有處理都遵守相應(yīng)的讀寫操作限制。
測(cè)試數(shù)據(jù)文件包括 n 行測(cè)試數(shù)據(jù),分別描述創(chuàng)建的 n 個(gè)線程是讀者還是寫者,以及讀寫操作的開始時(shí)間和持續(xù)時(shí)間。每行測(cè)試數(shù)據(jù)包括4個(gè)字段,各個(gè)字段間用空格分隔。
?
第一個(gè)字段為一個(gè)正整數(shù),表示線程序號(hào)
?
第二個(gè)字段表示相應(yīng)線程角色,R 表示讀者,W 表示寫者
?
第三個(gè)字段為一個(gè)正數(shù),表示讀/寫操作的開始時(shí)間:線程創(chuàng)建后,延遲相應(yīng)時(shí)間(單位為秒)后發(fā)出對(duì)共享資源的讀/寫請(qǐng)求
?
第四個(gè)字段為一正數(shù),表示讀/寫操作的持續(xù)時(shí)間:線程讀寫請(qǐng)求成功后,開始對(duì)共享資源的讀/寫操作,該操作持續(xù)相應(yīng)時(shí)間后結(jié)束,并釋放共享資源 例如: 1 R 3 5 2 W 4 5 3 R 5 2 4 R 6 5 5 W 5.1 3 讀者寫者問(wèn)題是操作系統(tǒng)中經(jīng)典的互斥問(wèn)題:一塊數(shù)據(jù)被多個(gè)讀者和寫者的訪問(wèn),需要考慮讀寫互斥、寫寫互斥(可以同時(shí)由多個(gè)讀者讀取)。具體的又可以分為讀者優(yōu)先和寫者優(yōu)先兩類。讀者優(yōu)先算法:
當(dāng)新的讀者到來(lái)的時(shí)候,若當(dāng)前正有讀者在進(jìn)行讀操作,則該讀者無(wú)需等待前面的寫操作完成,直接進(jìn)行讀操作。設(shè)置兩個(gè)互斥信號(hào)量:
rwmutex 用于寫者與其他讀者/寫者互斥的訪問(wèn)共享數(shù)據(jù) rmutex 用于讀者互斥的訪問(wèn)讀者計(jì)數(shù)器readcount var rwmutex, rmutex : semaphore := 1,1 ; int readcount = 0;cobegin
readeri begin // i=1,2,?.P(rmutex);
Readcount++;
If(readcount == 1)P(rwmutex);
V(rmutex);
讀數(shù)據(jù);
P(rmutex);
Readcount--;
If(readcount == 0)V(rwmutex);
V(rmutex);
End
Writerj begin // j = 1,2,?.P(rwmutex);
寫更新;
V(rwmutex);
End Coend 寫者優(yōu)先: 條件:
1)多個(gè)讀者可以同時(shí)進(jìn)行讀
2)寫者必須互斥(只允許一個(gè)寫者寫,也不能讀者寫者同時(shí)進(jìn)行)
3)寫者優(yōu)先于讀者(一旦有寫者,則后續(xù)讀者必須等待,喚醒時(shí)優(yōu)先考慮寫者)設(shè)置三個(gè)互斥信號(hào)量:
rwmutex 用于寫者與其他讀者/寫者互斥的訪問(wèn)共享數(shù)據(jù) rmutex 用于讀者互斥的訪問(wèn)讀者計(jì)數(shù)器readcount nrmutex 用于寫者等待已進(jìn)入讀者退出,所有讀者退出前互斥寫操作 var rwmutex, rmutex,nrmutex : semaphore := 1,1,1 ; int readcount = 0;cobegin
readeri begin // i=1,2,?.P(rwmutex);
P(rmutex);
Readcount++;
If(readcount == 1)P(nrmutex);//有讀者進(jìn)入,互斥寫操作
V(rmutex);
V(rwmutex);// 及時(shí)釋放讀寫互斥信號(hào)量,允許其它讀、寫進(jìn)程申請(qǐng)資源
讀數(shù)據(jù);
P(rmutex);
Readcount--;
If(readcount == 0)V(nrmutex);//所有讀者退出,允許寫更新
V(rmutex);
End
Writerj begin // j = 1,2,?.P(rwmutex);// 互斥后續(xù)其它讀者、寫者
P(nrmutex);//如有讀者正在讀,等待所有讀者讀完
寫更新;
V(nrmutex);//允許后續(xù)新的第一個(gè)讀者進(jìn)入后互斥寫操作
V(rwmutex);//允許后續(xù)新讀者及其它寫者
End Coend //////////////////////////////////////////////////////////////////////////////////////////////////////////////// /*---------函數(shù)聲明---------*/ void Creat_Writer();
//添加一個(gè)寫者 void Del_Writer();
//刪除一個(gè)寫者 void Creat_Reader();
//添加一個(gè)讀者
void Reader_goon();
//讀者進(jìn)程運(yùn)行函數(shù) void R_Wakeup();
//喚醒等待讀者 void Del_Reader();
//刪除一個(gè)讀者 void Show();
//顯示運(yùn)行狀態(tài)
/*===============
class
signal
===============*/ class signal //信號(hào)量對(duì)象.{ private: int value;int queue;
//用int型數(shù)據(jù)模擬等待隊(duì)列.public: signal();signal(int n);int P();//檢查臨界資源 int V();//釋放臨界資源 int Get_Value();int Get_Queue();};//////////////////////////////////////////////////////////////////// #include
#include
struct ThreadInfo
{
int num;
char type;
double start;
double time;
}thread_info[MaxThread];
HANDLE hX;
HANDLE hWsem;
HANDLE thread[MaxThread];int readcount;double totaltime;
void WRITEUNIT(int iProcess){
printf(“Thread %d begins to write.n”,iProcess);
Sleep((DWORD)(thread_info[iProcess-1].time*1000));
printf(“End of thread %d for writing.n”,iProcess);}
void READUNIT(int iProcess){
printf(“Thread %d begins to read.n”,iProcess);
Sleep((DWORD)(thread_info[iProcess-1].time*1000));
printf(“End of thread %d for reading.n”,iProcess);}
DWORD
WINAPI
reader(LPVOID
lpVoid){
int iProcess
=
*(int*)lpVoid;
Sleep((DWORD)(thread_info[iProcess-1].start*1000));
DWORD wait_for=WaitForSingleObject(hX,INFINITE);
printf(“Thread %d requres reading.n”,iProcess);
readcount++;
if(readcount==1)WaitForSingleObject(hWsem,INFINITE);
ReleaseMutex(hX);
READUNIT(iProcess);
wait_for=WaitForSingleObject(hX,INFINITE);
readcount--;
if(readcount==0)
ReleaseSemaphore(hWsem,1,0);
ReleaseMutex(hX);
return iProcess;}
DWORD
WINAPI
writer(LPVOID
lpVoid){
int iProcess
=
*(int*)lpVoid;
Sleep((DWORD)(thread_info[iProcess-1].start*1000));
printf(“Thread %d requres writing.n”,iProcess);
DWORD wait_for=WaitForSingleObject(hWsem,INFINITE);
WRITEUNIT(iProcess);
ReleaseSemaphore(hWsem,1,0);
return iProcess;}
int main(){
int threadNum;
int threadcount;
ifstream file;
hX=CreateMutex(NULL, FALSE, NULL);
hWsem=CreateSemaphore(NULL,1,1,NULL);
//???
readcount=0;
threadcount=0;
totaltime=0;
file.open(“thread.dat”,ios::in);
if(file==0)
{
printf(“File Open Error.n”);
return 0;
}
while(file>>threadNum)
{
thread_info[threadNum-1].num=threadNum;
file>>thread_info[threadNum-1].type;
file>>thread_info[threadNum-1].start;
file>>thread_info[threadNum-1].time;
totaltime+=thread_info[threadNum-1].time;
switch(thread_info[threadNum-1].type)
{
case 'W':
printf(“Creating Thread %d writing.n”,thread_info[threadNum-1].num);
thread[threadNum-1]
=
CreateThread(NULL, &thread_info[threadNum-1].num,0,0);
break;
case 'R':
printf(“Creating Thread %d reading.n”,thread_info[threadNum-1].num);
thread[threadNum-1]
=
CreateThread(NULL, &thread_info[threadNum-1].num,0,0);
break;
}
threadcount++;
}
file.close();
Sleep((DWORD)(totaltime*1000));
return 1;} ////////////////////////////////////////////////////////////////////////////////// semaphore fmutex = 1 , rdcntmutex = 1;// fmutex--> access to file;rdcntmutex--> access to readcount int readcount = 0;void reader(){
while(1)
for 0,writer, for 0,reader,{
P(rdcntmutex);
if(readcount==0)
P(fmutex);
readcount = readcount + 1;
V(rdcntmutex);
// Do read operation
P(rdcntmutex);
readcount = readcount1;
if(readcount==0)
V(fmutex);
V(rdcntmutex);
} } void writer(){
while(1)
{
P(wtcntmutex);
if(writecount==0)
P(queue);
writecount = writecount + 1;
V(wtcntmutex);
P(fmutex);
// Do write operation
V(fmutex);
P(wtcntmutex);
writecount = writecount-1;
if(writecount==0)
V(queue);
V(wtcntmutex);
} }
第二篇:操作系統(tǒng)讀者寫者實(shí)驗(yàn)報(bào)告
目錄
一 設(shè)計(jì)概述 ……………………………………………………2
二 設(shè)計(jì)目的與內(nèi)容 ……………………………………………3
三 設(shè)計(jì)分析 ……………………………………………………4
四 程序?qū)崿F(xiàn) ……………………………………………………5
五 程序調(diào)試 ……………………………………………………6
六 結(jié)果分析和討論 ……………………………………………6
七 心得體會(huì) ……………………………………………………7
八 源代碼 ………………………………………………………7
一 設(shè)計(jì)概述
所謂讀者寫者問(wèn)題,是指保證一個(gè)writer進(jìn)程必須與其他進(jìn)程互斥地訪問(wèn)共享對(duì)象的同步問(wèn)題。
讀者寫者問(wèn)題可以這樣的描述,有一群寫者和一群讀者,寫者在寫同一本書,讀者也在讀這本書,多個(gè)讀者可以同時(shí)讀這本書,但是,只能有一個(gè)寫者在寫書,并且,讀者必寫者優(yōu)先,也就是說(shuō),讀者和寫者同時(shí)提出請(qǐng)求時(shí),讀者優(yōu)先。當(dāng)讀者提出請(qǐng)求時(shí)需要有一個(gè)互斥操作,另外,需要有一個(gè)信號(hào)量S來(lái)當(dāng)前是否可操作。
信號(hào)量機(jī)制是支持多道程序的并發(fā)操作系統(tǒng)設(shè)計(jì)中解決資源共享時(shí)進(jìn)程間的同步與互斥的重要機(jī)制,而讀者寫者問(wèn)題則是這一機(jī)制的一個(gè)經(jīng)典范例。
與記錄型信號(hào)量解決讀者—寫者問(wèn)題不同,信號(hào)量機(jī)制它增加了一個(gè)限制,即最多允許RN個(gè)讀者同時(shí)讀。為此,又引入了一個(gè)信號(hào)量L,并賦予初值為RN,通過(guò)執(zhí)行wait(L,1,1)操作,來(lái)控制讀者的數(shù)目,每當(dāng)有一個(gè)讀者進(jìn)入時(shí),就要執(zhí)行wait(L,1,1)操作,使L的值減1。當(dāng)有RN個(gè)讀者進(jìn)入讀后,L便減為0,第RN+1 個(gè)讀者要進(jìn)入讀時(shí),必然會(huì)因wait(L,1,1)操作失敗而堵塞。對(duì)利用信號(hào)量來(lái)解決讀者—寫者問(wèn)題的描述如下: Var RN integer;L,mx:semaphore: =RN,1; Begin Parbegin Reader :begin Repeat Swait(L,1,1);Swait(mx,1,0);.Perform reader operation;Ssignal(L,1);Until false;End Writer :begin Repeat Swait(mx ,1,1,l,RN,0);Perform writer operation;Ssignal(mx,1);Until false;End Parend End 其中,Swait(mx,1,0)語(yǔ)句起著開關(guān)作用,只要無(wú)Writer進(jìn)程進(jìn)入些,mx=1,reader進(jìn)程就都可以進(jìn)入讀。但是要一旦有Writer進(jìn)程進(jìn)入寫時(shí),其MX=0,則任何reader進(jìn)程就都無(wú)法進(jìn)入讀。Swait(mx ,1,1,l,RN,0)語(yǔ)句表示僅當(dāng)既無(wú)Write進(jìn)程在寫(mx=1),又無(wú)reader進(jìn)程在讀(L=RN)時(shí),writer進(jìn)程才能進(jìn)入臨界區(qū)寫。
本設(shè)計(jì)方案就是通過(guò)利用記錄型信號(hào)量對(duì)讀者寫者問(wèn)題的解決過(guò)程進(jìn)行模擬演示,形象地闡述記錄型信號(hào)量機(jī)制的工作原理。
二 設(shè)計(jì)目的與內(nèi)容
一 實(shí)驗(yàn)?zāi)康?/p>
l.用信號(hào)量來(lái)實(shí)現(xiàn)讀者寫者問(wèn)題。
2.理解和運(yùn)用信號(hào)量、PV原語(yǔ)、進(jìn)程間的同步互斥關(guān)系等基本知識(shí)。
二、二 實(shí)驗(yàn)內(nèi)容
讀者寫者問(wèn)題的定義如下:有一個(gè)許多進(jìn)程共享的數(shù)據(jù)區(qū),這個(gè)數(shù)據(jù)區(qū)可以是一個(gè)文件或者主存的一塊空間;有一些只讀取這個(gè)數(shù)據(jù)區(qū)的進(jìn)程(Reader)和一些只往數(shù)據(jù)區(qū)寫數(shù)據(jù)的進(jìn)程(Writer),此外還需要滿足以下條件:
(1)任意多個(gè)讀進(jìn)程可以同時(shí)讀這個(gè)文件;(2)一次只有一個(gè)寫進(jìn)程可以往文件中寫;
(3)如果一個(gè)寫進(jìn)程正在進(jìn)行操作,禁止任何讀進(jìn)程度文件。我們需要分兩種情況實(shí)現(xiàn)該問(wèn)題:
讀優(yōu)先:要求指一個(gè)讀者試圖進(jìn)行讀操作時(shí),如果這時(shí)正有其他讀者在進(jìn)行操作,他可直接開始讀操作,而不需要等待。
寫優(yōu)先:一個(gè)讀者試圖進(jìn)行讀操作時(shí),如果有其他寫者在等待進(jìn)行寫操作或正在進(jìn)行寫操作,他要等待該寫者完成寫操作后才開始讀操作。
三設(shè)計(jì)分析
在Windows 7 環(huán)境下,創(chuàng)建一個(gè)包含n 個(gè)線程的控制臺(tái)進(jìn)程。用這n 個(gè)線程來(lái)表示n個(gè)讀者或?qū)懻摺C總€(gè)線程按相應(yīng)測(cè)試數(shù)據(jù)文件的要求,進(jìn)行讀寫操作。請(qǐng)用信號(hào)量機(jī)制分別實(shí)現(xiàn)讀者優(yōu)先和寫者優(yōu)先的讀者-寫者問(wèn)題。
讀者-寫者問(wèn)題的讀寫操作限制:
讀者-寫者的讀寫限制(包括讀者優(yōu)先和寫者優(yōu)先)1)寫-寫互斥,即不能有兩個(gè)寫者同時(shí)進(jìn)行寫操作
2)讀-寫互斥,即不能同時(shí)有一個(gè)讀者在讀,同時(shí)卻有一個(gè)寫者在寫 3)讀讀允許,即可以有2個(gè)以上的讀者同時(shí)讀
將所有的讀者和所有的寫者分別放進(jìn)兩個(gè)等待隊(duì)列中,當(dāng)讀允許時(shí)就讓讀者隊(duì)列釋放一個(gè)或多個(gè)讀者,當(dāng)寫允許時(shí),釋放第一個(gè)寫者操作。讀者寫者問(wèn)題的定義如下:有一個(gè)許多進(jìn)程共享的數(shù)據(jù)區(qū),這個(gè)數(shù)據(jù)區(qū)可以是一個(gè)文件或者主存的一塊空間;有一些只讀取這個(gè)數(shù)據(jù)區(qū)的進(jìn)程(Reader)和一些只往數(shù)據(jù)區(qū)寫數(shù)據(jù)的進(jìn)程(Writer),此外還需要滿足以下條件:1)任意多個(gè)讀進(jìn)程可以同時(shí)讀這個(gè)文件;2)一次只有一個(gè)寫進(jìn)程可以往文件中寫;3)如果一個(gè)寫進(jìn)程正在進(jìn)行操作,禁止任何讀進(jìn)程度文件。我們需要分兩種情況實(shí)現(xiàn)該問(wèn)題:
讀優(yōu)先:要求指一個(gè)讀者試圖進(jìn)行讀操作時(shí),如果這時(shí)正有其他讀者在進(jìn)行操作,他可直接開始讀操作,而不需要等待。寫優(yōu)先:一個(gè)讀者試圖進(jìn)行讀操作時(shí),如果有其他寫者在等待進(jìn)行寫操作或正在進(jìn)行寫操作,他要等待該寫者完成寫操作后才開始讀操作。
四 程序?qū)崿F(xiàn)
程序由兩部分組成:
1。讀者-寫者模塊:包括系統(tǒng)調(diào)用接口,讀者-寫者活動(dòng)描述主程序。系統(tǒng)接口主要功能是通過(guò)管道向父進(jìn)程發(fā)送系統(tǒng)調(diào)用命令,并讀取父進(jìn)程送來(lái)的返回值。
讀者-寫者活動(dòng)程序根據(jù)臨界資源的共享,互斥原則編制,具體見源程序。2。主控模塊:主控模塊實(shí)現(xiàn)系統(tǒng)初始化系統(tǒng)調(diào)用命令接收與解釋執(zhí)行,系統(tǒng)調(diào)用功能的實(shí)現(xiàn)(包括信號(hào)量機(jī)制),及讀者-寫者活動(dòng)過(guò)程記錄與顯示。
初始化系統(tǒng)環(huán)境 建立通信管道
啟動(dòng)讀者-寫者進(jìn)程 接收系統(tǒng)調(diào)用命令 解釋執(zhí)行
系統(tǒng)初始化模塊 管道建立模塊 進(jìn)程啟動(dòng)模塊 命令解釋模塊 Wait()Signal()Wakeup()Block()
五 程序調(diào)試
測(cè)試數(shù)據(jù)文件格式: 測(cè)試數(shù)據(jù)文件包括n 行測(cè)試數(shù)據(jù),分別描述創(chuàng)建的n 個(gè)線程是讀者還是寫者,以及讀寫操作的開始時(shí)間和持續(xù)時(shí)間。每行測(cè)試數(shù)據(jù)包括四個(gè)字段,各字段間用空格分隔。第一字段為一個(gè)正整數(shù),表示線程序號(hào)。第二字段表示相應(yīng)線程角色,R 表示讀者是,W 表示寫者。第三字段為一個(gè)正數(shù),表示讀寫操作的開始時(shí)間。線程創(chuàng)建后,延時(shí)相應(yīng)時(shí)間(單位為秒)后發(fā)出對(duì)共享資源的讀寫申請(qǐng)。第四字段為一個(gè)正數(shù),表示讀寫操作的持續(xù)時(shí)間。當(dāng)線程讀寫申請(qǐng)成功后,開始對(duì)共享資源的讀寫操作,該操作持續(xù)相應(yīng)時(shí)間后結(jié)束,并釋放共享資源。
六 結(jié)果分析和討論
在讀者寫者同時(shí)在隊(duì)列中等待申請(qǐng)資時(shí),讀者優(yōu)先調(diào)用資源。而且如果一個(gè)讀者申請(qǐng)進(jìn)行讀操作時(shí)已有另一讀者正在進(jìn)行讀操作,則該讀者可直接開始讀操作,即讀讀允許。
進(jìn)程1是R操作,在時(shí)間3時(shí)進(jìn)入隊(duì)列,運(yùn)行時(shí)間是5,在它進(jìn)入時(shí)沒有進(jìn)程占用資源,它既占用資源;知道它釋放資源,等候的進(jìn)程有3,4,5;
進(jìn)程2是W操作,在時(shí)間16時(shí)進(jìn)入隊(duì)列,運(yùn)行時(shí)間是5,在它進(jìn)入時(shí)進(jìn)程4占用資源,它等待資源,當(dāng)4釋放時(shí)占用資源;
進(jìn)程3是R操作,在時(shí)間5時(shí)進(jìn)入隊(duì)列,運(yùn)行時(shí)間是2,在它進(jìn)入時(shí)進(jìn)程1占用資源,它等待資源,當(dāng)進(jìn)程1釋放資源后,由于讀者優(yōu)先,進(jìn)程3,5同時(shí)調(diào) 運(yùn)資源;
進(jìn)程4是R操作,在時(shí)間6時(shí)進(jìn)入隊(duì)列,運(yùn)行時(shí)間是5,在它進(jìn)入時(shí)進(jìn)程1占用資源,它等待資源,當(dāng)進(jìn)程1釋放資源后,由于讀者優(yōu)先,進(jìn)程3,5占用資源,它依然等待,直到進(jìn)程3,5都結(jié)束;
進(jìn)程5是W操作,在時(shí)間4時(shí)進(jìn)入隊(duì)列,運(yùn)行時(shí)間是3, 在它進(jìn)入時(shí)進(jìn)程1占用資源,它等待資源,當(dāng)進(jìn)程1釋放資源后,由于讀者優(yōu)先,進(jìn)程3,5同時(shí)調(diào)運(yùn)資源;
七 心得體會(huì)
這一次課程設(shè)計(jì),讓我體會(huì)很深刻。讀者-寫者問(wèn)題經(jīng)典的線程同步問(wèn)題的一個(gè)模型。經(jīng)過(guò)讀者寫者問(wèn)題的編寫,我對(duì)同步機(jī)構(gòu)應(yīng)用有了深入的了解。懂得了運(yùn)用信號(hào)量實(shí)現(xiàn)進(jìn)程間的互斥。實(shí)現(xiàn)了不讓共享資源同時(shí)修改。用信號(hào)量上的原語(yǔ)操作使臨界段問(wèn)題的解決比較簡(jiǎn)單明了了。讀者寫者問(wèn)題的編寫,花的時(shí)間很多,也學(xué)到很多東西。了解支持多道程序的并發(fā)操作系統(tǒng)設(shè)計(jì)中解決資源共享時(shí)進(jìn)程間的同步與互斥的信號(hào)量機(jī)制。幾天的試驗(yàn),雖然難度有點(diǎn)大,但只要自己花時(shí)間去學(xué)習(xí),還是會(huì)攻克困難的。
總之,每一次課程設(shè)計(jì)不僅是我們學(xué)習(xí)的好機(jī)會(huì),而且是我們鍛煉實(shí)際動(dòng)手能力的平臺(tái),雖然有難度的東西總會(huì)讓人很抵觸,比如在課設(shè)過(guò)程中有很多郁悶的時(shí)候,一個(gè)小小的錯(cuò)誤一不小心就花去了自己一上午的時(shí)間,所以在這個(gè)過(guò)程中能夠磨練人的意志與耐心,最后感謝老師的指導(dǎo)與監(jiān)督。
八 源代碼
#include
第三篇:讀者-寫者 操作系統(tǒng)實(shí)驗(yàn)報(bào)告 計(jì)算機(jī)操作系統(tǒng)
4.1實(shí)驗(yàn)二:讀者寫者問(wèn)題 4.1.1實(shí)驗(yàn)要求
在Windows 環(huán)境下,創(chuàng)建一個(gè)控制臺(tái)進(jìn)程,此進(jìn)程包含n個(gè)線程。用這n個(gè)線程來(lái)表示n個(gè)讀者或?qū)懻?。每個(gè)線程按相應(yīng)測(cè)試數(shù)據(jù)文件(后面有介紹)的要求進(jìn)行讀寫操作。用信號(hào)量機(jī)制分別實(shí)現(xiàn)讀者優(yōu)先和寫者優(yōu)先的讀者-寫者問(wèn)題。
讀者-寫者問(wèn)題的讀寫操作限制(包括讀者優(yōu)先和寫者優(yōu)先): 1)寫-寫互斥,即不能有兩個(gè)寫者同時(shí)進(jìn)行寫操作。
2)讀-寫互斥,即不能同時(shí)有一個(gè)線程在讀,而另一個(gè)線程在寫。3)讀-讀允許,即可以有一個(gè)或多個(gè)讀者在讀。
讀者優(yōu)先的附加限制:如果一個(gè)讀者申請(qǐng)進(jìn)行讀操作時(shí)已有另一個(gè)讀者正在進(jìn)行讀操作,則該讀者可直接開始讀操作。
寫者優(yōu)先的附加限制:如果一個(gè)讀者申請(qǐng)進(jìn)行讀操作時(shí)已有另一寫者在等待訪問(wèn)共享資源,則該讀者必須等到?jīng)]有寫者處于等待狀態(tài)才能開始讀操作。
運(yùn)行結(jié)果顯示要求:要求在每個(gè)線程創(chuàng)建、發(fā)出讀寫操作申請(qǐng)、開始讀寫操作和結(jié)果讀寫操作時(shí)分別顯示一行提示信息,以確定所有處理都遵守相應(yīng)的讀寫操作限制。4.1.2測(cè)試數(shù)據(jù)文件格式
測(cè)試數(shù)據(jù)文件包括n行測(cè)試數(shù)據(jù),分別描述創(chuàng)建的n個(gè)線程是讀者還是寫者,以及讀寫操作的開始時(shí)間和持續(xù)時(shí)間。每行測(cè)試數(shù)據(jù)包括四個(gè)字段,各個(gè)字段間用空格分隔。第一字段為一個(gè)正整數(shù),表示線程序號(hào)。第二字段表示相應(yīng)線程角色,R表示讀者,W表示寫者。第三字段為一個(gè)正數(shù),表示讀寫操作的開始時(shí)間:線程創(chuàng)建后,延遲相應(yīng)時(shí)間(單位為秒)后發(fā)出對(duì)共享資源的讀寫申請(qǐng)。第四字段為一個(gè)正數(shù),表示讀寫操作的持續(xù)時(shí)間。當(dāng)線程讀寫申請(qǐng)成功后,開始對(duì)共享資源的讀寫操作,該操作持續(xù)相應(yīng)時(shí)間后結(jié)束,并釋放共享資源。
下面是一個(gè)測(cè)試數(shù)據(jù)文件的例子: 1 R 3 5 2 W 4 5 3 R 5 2 4 R 6 5 5 W 5.1 3 注意:
在創(chuàng)建數(shù)據(jù)文件時(shí),由于涉及到文件格式問(wèn)題,最好在記事本中手工逐個(gè)鍵入數(shù)據(jù),而不要拷貝粘貼數(shù)據(jù),否則,本示例程序運(yùn)行時(shí)可能會(huì)出現(xiàn)不可預(yù)知的錯(cuò)誤。4.1.3實(shí)習(xí)分析
可以將所有讀者和所有寫者分別存于一個(gè)讀者等待隊(duì)列和一個(gè)寫者等待隊(duì)列中,每當(dāng)讀允許時(shí),就從讀者隊(duì)列中釋放一個(gè)或多個(gè)讀者線程進(jìn)行讀操作;每當(dāng)寫允許時(shí),就從寫者隊(duì)列中釋放一個(gè)寫者進(jìn)行寫操作。
1.讀者優(yōu)先
讀者優(yōu)先指的是除非有寫者在寫文件,否則讀者不需要等待。所以可以用一個(gè)整型變量read-count記錄當(dāng)前的讀者數(shù)目,用于確定 是否需要釋放正在等待的寫者線程(當(dāng)read-count=0時(shí),表明所有的讀者讀完,需要釋放寫者等待隊(duì)列中的一個(gè)寫者)。每一個(gè)讀者開始讀文件時(shí),必須修改read-count變量。因此需要一個(gè)互斥對(duì)象mutex來(lái)實(shí)現(xiàn)對(duì)全局變量read-count修改時(shí)的互斥。
另外,為了實(shí)現(xiàn)寫-寫互斥,需要增加一個(gè)臨界區(qū)對(duì)象write。當(dāng)寫者發(fā)出寫請(qǐng)求時(shí),必須申請(qǐng)臨界區(qū)對(duì)象的所有權(quán)。通過(guò)這種方法,也可以實(shí)現(xiàn)讀-寫互斥,當(dāng)read-count=1時(shí)(即第一個(gè)讀者到來(lái)時(shí)),讀者線程也必須申請(qǐng)臨界區(qū)對(duì)象的所有權(quán)。當(dāng)讀者擁有臨界區(qū)的所有權(quán)時(shí),寫者阻塞在臨界區(qū)對(duì)象write上。當(dāng)寫者擁有臨界區(qū)的所有權(quán)時(shí),第一個(gè)讀者判斷完“read-count==1”后阻塞在write上,其余的讀者由于等待對(duì)read-count的判斷,阻塞在mutex上。
2.寫者優(yōu)先
寫者優(yōu)先與讀者優(yōu)先類似。不同之處在于一旦一個(gè)寫者到來(lái),它應(yīng)該盡快對(duì)文件進(jìn)行寫操作,如果有一個(gè)寫者在等待,則新到來(lái)的讀者不允許進(jìn)行讀操作。為此應(yīng)當(dāng)添加一個(gè)整型變量write-count,用于記錄正在等待的寫者數(shù)目,當(dāng)write-count=0時(shí),才可以釋放等待的讀者線程隊(duì)列。
為了對(duì)全局變量write-count實(shí)現(xiàn)互斥,必須增加一個(gè)互斥對(duì)象mutex3。
為了實(shí)現(xiàn)寫者優(yōu)先,應(yīng)當(dāng)添加一個(gè)臨界區(qū)對(duì)象read,當(dāng)有寫者在寫文件或等待時(shí),讀者必須阻塞在read上。
讀者線程除了要對(duì)全局變量read-count實(shí)現(xiàn)操作上的互斥外,還必須有一個(gè)互斥對(duì)象對(duì)阻塞read這一過(guò)程實(shí)現(xiàn)互斥。這兩個(gè)互斥對(duì)象分別命名為mutex1和mutex2。4.1.4相關(guān)API函數(shù)說(shuō)明
1.CreateThread 函數(shù)功能:
該函數(shù)創(chuàng)建一個(gè)在調(diào)用進(jìn)程的地址空間中執(zhí)行的線程。函數(shù)原型:
HANDLE CreateThread(LPSECURITY-ATTRIBUTES lpThreadAttributes, DWORD dwStackSize,LPTHREAD-START-TOUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LLPDWORD lpThreadId);參數(shù):
·lpThreadAttributes:指向一個(gè)SECURITY-ATTRIBUTES結(jié)構(gòu),該結(jié)構(gòu)決定了返回的句柄是否可被子進(jìn)程繼承。若lpThreadAttributes為NULL,則句柄不能被繼承。在Windows NT中該結(jié)構(gòu)的lpSwcurityDescriptor成員定義了新進(jìn)程的安全性描述符。若lpThreadAttributes為NULL,則線程獲得一個(gè)默認(rèn)的安全性描述符?!wStackSize:定義原始堆棧提交時(shí)的大小(按字節(jié)計(jì))。系統(tǒng)將該值舍入為最近的頁(yè)。若該值為0,或小于默認(rèn)時(shí)提交的大小,默認(rèn)情況是使用與調(diào)用線程同樣的大小。更多的信息,請(qǐng)看Thread Stack Size。
·lpStartAddress:指向一個(gè)LPTHREAD-START-TOUTINE類型的應(yīng)用定義的函數(shù),該線程執(zhí)行此函數(shù)。該指針還表示遠(yuǎn)程進(jìn)程中線程的起始地址。該函數(shù)必須存在于遠(yuǎn)程進(jìn)程中。
·lpParameter:定義一個(gè)傳遞給該進(jìn)程的32位值。
·dwCreationFlags:定義控制進(jìn)程創(chuàng)建的附加標(biāo)志。若定義CREATE-SUSPENDED標(biāo)志,線程創(chuàng)建時(shí)處于掛起狀態(tài),并且直到ResumeThread函數(shù)調(diào)用時(shí)才能運(yùn)行。若該值為0,則該線程在創(chuàng)建后立即執(zhí)行。
·lpThreadId:指向一個(gè)32位值,它接收該線程的標(biāo)識(shí)符。返回值:
若函數(shù)調(diào)用成功,返回值為新線程的句柄;若函數(shù)調(diào)用失敗,返回值為NULL。備注:
新線程的句柄創(chuàng)建時(shí)設(shè)為THREAD-ALL-ACCESS訪問(wèn)權(quán)限。若未提供安全性描述符,則該句柄可被任何要求一個(gè)線程對(duì)象句柄的函數(shù)所使用。若提供了安全性描述符,則以后使用該句柄時(shí),將在授權(quán)訪問(wèn)以前執(zhí)行訪問(wèn)檢查。若訪問(wèn)檢查被拒絕訪問(wèn),則請(qǐng)求進(jìn)程不能使用該句柄獲得對(duì)該線程的訪問(wèn)。線程從lpStartAddress參數(shù)定義的函數(shù)處開始執(zhí)行。若該函數(shù)返回,系統(tǒng)將默認(rèn)地認(rèn)為以調(diào)用ExitThread函數(shù)的方法終止該線程。使用GetExitCodeThread 函數(shù)來(lái)獲得線程的返回值。
線程創(chuàng)建時(shí)擁有THREAD-PRIORITY-NORMAL優(yōu)先權(quán)。使用GetThreadPriority和SetThreadPriority函數(shù)可以獲得和設(shè)置線程的優(yōu)先權(quán)值。
一個(gè)線程終止時(shí),該線程對(duì)象被設(shè)為發(fā)信號(hào)狀態(tài),以滿足在該對(duì)象上等待的所有進(jìn)程。一個(gè)線程對(duì)象始終存在于系統(tǒng)中,直到該線程終止,且它所有的句柄都已通過(guò)調(diào)用CloseHandle函數(shù)關(guān)閉。
2.ExitThread 函數(shù)功能:
該函數(shù)結(jié)束一個(gè)線程。函數(shù)原型:
VOID ExitThread(DWORD dwExitcode); 參數(shù):
·dwExitcode:定義調(diào)用線程的退出代碼。使用GetExitcodeThread函數(shù)來(lái)檢測(cè)一個(gè)線程的退出代碼。返回值:無(wú)。備注:
調(diào)用ExitThread函數(shù),是結(jié)束一個(gè)線程的較好的方法。調(diào)用該函數(shù)后(或者直接地調(diào)用,或者從一個(gè)線程過(guò)程返回),當(dāng)前線程的堆棧取消分配,線程終止。若調(diào)用該函數(shù)時(shí),該線程為進(jìn)程的最后一個(gè)線程,則該線程的進(jìn)程也被終止。
線程對(duì)象的狀態(tài)變?yōu)榘l(fā)信號(hào)狀態(tài),以釋放所有正在等待該線程終止的其他線程。線程的終止?fàn)顟B(tài)從STILL-ACTIVATE變?yōu)閐wExitcode參數(shù)的值。
線程結(jié)合時(shí)不必從操作系統(tǒng)中移去該線程對(duì)象。當(dāng)線程的最后一個(gè)句柄關(guān)閉時(shí),該線程對(duì)象被刪除。
3.SLEEP 函數(shù)功能:
該函數(shù)對(duì)于指定的時(shí)間間隔掛起當(dāng)前的執(zhí)行線程。函數(shù)原型:
VOID SLEEP(DWORD dwMilliseconds); 參數(shù):
·dwMilliseconds:定義掛起執(zhí)行線程的時(shí)間,以毫秒(ms)為單位。取值為0時(shí),該線程將如余下的時(shí)間片交給處于就緒狀態(tài)的同一優(yōu)先級(jí)的其他線程。若沒有處于就緒狀態(tài)的同一優(yōu)先級(jí)的其他線程,則函數(shù)立即返回,該線程繼續(xù)執(zhí)行。若取值為INFINITE則造成無(wú)限延遲。返回值:
該函數(shù)沒有返回值。備注:
一個(gè)線程可以在調(diào)用該函數(shù)時(shí)將睡眠時(shí)間設(shè)為0ms,以將剩余的時(shí)間片交出。4.CreateMutex 函數(shù)功能:
該函數(shù)創(chuàng)建有名或者無(wú)名的互斥對(duì)象。函數(shù)原型:
HANDLE CreateMutex(LPSECURITY-ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner,LPCTSTR lpName);參數(shù):
·lpMutexAttributes:指向SECURITY-ATTRIBUTES結(jié)構(gòu)的指針,該結(jié)構(gòu)決定子進(jìn)程是否能繼承返回句柄。如果lpMutexAttributes為NULL,那么句柄不能被繼承。
在Windows NT中該結(jié)構(gòu)的lpSwcurityDescriptor成員指定新互斥對(duì)象的安全性描述符。若lpThreadAttributes為NULL,那么互斥對(duì)象獲得默認(rèn)的安全性描述符。·bInitialOwner:指定互斥對(duì)象的初始所屬身份。如果該值為TRUE,并且調(diào)用者創(chuàng)建互斥對(duì)象,那么調(diào)用線程獲得互斥對(duì)象所屬身份。否則,調(diào)用線程不能獲得互斥對(duì)象所屬身份。判斷調(diào)用者是否創(chuàng)建互斥對(duì)象請(qǐng)參閱返回值部分。
·lpName:指向以NULL結(jié)尾的字符串,該字符串指定了互斥對(duì)象名。該名字的長(zhǎng)度大于MAX-PATH且可以包含除反斜線()路徑分隔符以外的任何字符。名字是區(qū)分大小寫的。
如果lpName與已存在的有名互斥對(duì)象相匹配,那么該函數(shù)要求用MUTEX-ALL-ACCESS權(quán)限訪問(wèn)已存在的對(duì)象。在這種情況下,由于參數(shù)bInitialOwner已被創(chuàng)建進(jìn)程所設(shè)置,該參數(shù)被忽略。如果參數(shù)lpMutexAttributes不為NULL,它決定句柄是否解除繼承,但是其安全描述符成員被忽略。
如果lpName為NULL,那么創(chuàng)建的互斥對(duì)象無(wú)名。
如果lpName與已存在的事件、信號(hào)量、可等待定時(shí)器、作業(yè)或者文件映射對(duì)象的名字相匹配,那么函數(shù)調(diào)用失敗,并且GetLastError函數(shù)返回ERROR-INVALID-HANDLE,其原因是這些對(duì)象共享相同的名字空間。
返回值:
如果函數(shù)調(diào)用成功,返回值為互斥對(duì)象句柄;如果函數(shù)調(diào)用之前,有名互斥對(duì)象已存在,那么函數(shù)給已存在的對(duì)象返回一個(gè)句柄,并且函數(shù)GetLastError返回ERROR-ALREADY-EXISTS,否則,調(diào)用者創(chuàng)建互斥對(duì)象。
如果函數(shù)調(diào)用失敗,則返回值為NULL。若想獲得更多錯(cuò)誤信息,請(qǐng)調(diào)用GetLastError函數(shù)。
備注:
由函數(shù)CreateMutex返回的句柄有MUTEX-ALL-ACCESS權(quán)限可以去訪問(wèn)新的互斥對(duì)象,并且可用在請(qǐng)求互斥對(duì)象句柄的任何函數(shù)中。
調(diào)用進(jìn)程中的任何線程可以可以在調(diào)用等待函數(shù)時(shí)指定互斥對(duì)象句柄。當(dāng)指定對(duì)象的狀態(tài)為信號(hào)態(tài)時(shí),返回單對(duì)象等待函數(shù)。當(dāng)任何一個(gè)或者所有的互斥對(duì)象都為信號(hào)態(tài)時(shí),返回多對(duì)象等待函數(shù)指令。等待函數(shù)返回后,等待的線程被釋放,繼續(xù)向下執(zhí)行。
當(dāng)一個(gè)互斥對(duì)象不被任何線程擁有時(shí),處于信號(hào)態(tài)。創(chuàng)建該對(duì)象的線程可以使用bInitialOwner標(biāo)志來(lái)請(qǐng)求立即獲得對(duì)該互斥對(duì)象的所有權(quán)。否則,線程必須使用等待函數(shù)來(lái)請(qǐng)求所有權(quán)。當(dāng)互斥對(duì)象處于信號(hào)態(tài),等待的線程獲得對(duì)該對(duì)象的所有權(quán)時(shí),此互斥對(duì)象的狀態(tài)被設(shè)置為非信號(hào)態(tài),等待函數(shù)返回。任意時(shí)刻,僅有一個(gè)線程能擁有該互斥對(duì)象,線程可以使用ReleaseMutex函數(shù)來(lái)釋放對(duì)這個(gè)互斥對(duì)象的所有權(quán)。
若線程已經(jīng)擁有了一個(gè)互斥對(duì)象,那么它可以重復(fù)調(diào)用等待函數(shù)而不會(huì)發(fā)生阻塞,一般情況下,用戶不會(huì)重復(fù)等待同一個(gè)互斥對(duì)象,這種機(jī)制防止了線程因等待它已經(jīng)擁有的互斥對(duì)象而發(fā)生死鎖。然而,線程必須為每一次等待調(diào)用一次ReleaseMutex函數(shù)來(lái)釋放該互斥對(duì)象。
兩個(gè)或多個(gè)互斥進(jìn)程可以調(diào)用CreateMutex來(lái)創(chuàng)建同名的互斥對(duì)象,第一個(gè)進(jìn)程實(shí)際創(chuàng)建互斥對(duì)象,以后的進(jìn)程打開已存在的互斥對(duì)象的句柄。這使得多個(gè)進(jìn)程可以得到同一個(gè)互斥對(duì)象的句柄,從而減輕了用戶的負(fù)擔(dān),使用戶不必判斷創(chuàng)建進(jìn)程是否為第一個(gè)啟動(dòng)的進(jìn)程。使用這種技術(shù)時(shí),應(yīng)該把bInitialOwner標(biāo)志設(shè)為FALSE;否則很難確定開始時(shí)哪一個(gè)進(jìn)程擁有該互斥對(duì)象。
由于多進(jìn)程能夠擁有相同互斥對(duì)象的句柄,通過(guò)使用這個(gè)對(duì)象,可使多進(jìn)程同步。以下為共享對(duì)象機(jī)制:
·如果CreateMutex中的lpMutexAttributes參數(shù)允許繼承,由CreateProcess函數(shù)創(chuàng)建的子進(jìn)程可以繼承父進(jìn)程的互斥對(duì)象句柄。
·一個(gè)進(jìn)程可以在調(diào)用DuplicateHandle函數(shù)時(shí)指定互斥對(duì)象句柄來(lái)創(chuàng)建一個(gè)可以被其他進(jìn)程使用的雙重句柄。一個(gè)進(jìn)程在調(diào)用OpenMutex或CreateMutex函數(shù)時(shí)能指定互斥對(duì)象名。
·使用CloseHandle函數(shù)關(guān)閉句柄,進(jìn)程時(shí)系統(tǒng)自動(dòng)關(guān)閉句柄。當(dāng)最后一個(gè)句柄被關(guān)閉時(shí),互斥對(duì)象被銷毀。
5.ReleaseMutex 函數(shù)功能:
該函數(shù)放棄指定互斥對(duì)象的所有權(quán)。函數(shù)原型:
BOOL ReleaseMutex(HANDLE hMutex); 參數(shù):
·hMutex:互斥對(duì)象句柄。為CreateMutex或OpenMutex函數(shù)的返回值。返回值:
如果函數(shù)調(diào)用成功,那么返回值是非零值;如果函數(shù)調(diào)用失敗,那么返回值是零值。若想獲得更多錯(cuò)誤信息,請(qǐng)調(diào)用GetLastError函數(shù)。
備注:
如果調(diào)用線程不擁有互斥對(duì)象,ReleaseMutex函數(shù)失敗。一個(gè)線程通過(guò)調(diào)用等待函數(shù)擁有互斥對(duì)象。創(chuàng)建該互斥對(duì)象的線程也擁有互斥對(duì)象,而不需要調(diào)用等待函數(shù)。當(dāng)互斥對(duì)象的所有者線程不再需要互斥對(duì)象時(shí),它可以調(diào)用ReleaseMutex函數(shù)。
當(dāng)一個(gè)線程擁有一個(gè)互斥對(duì)象后,它可以用該互斥對(duì)象多次調(diào)用等待函數(shù)而不會(huì)阻塞。這防止一個(gè)線程等待一個(gè)它擁有的互斥對(duì)象時(shí)出現(xiàn)死鎖。不過(guò),為了釋放所有權(quán),該線程必須為每一個(gè)等待操作調(diào)用一次ReleaseMutex函數(shù)。
6.WaitForSingleObject 函數(shù)功能:
當(dāng)下列情況之一發(fā)生時(shí)該函數(shù)返回:(1)指定對(duì)象處于信號(hào)態(tài);(2)超時(shí)。函數(shù)原型:
DWORD waitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);參數(shù):
·hHandle:等待對(duì)象句柄。若想了解指定句柄的對(duì)象類型列表,參閱下面?zhèn)渥⒉糠帧?/p>
在Windows NT中,句柄必須有SYNCHRONIZE訪問(wèn)權(quán)限。若想獲得更多的信息,請(qǐng)查看Standard Access Rights。
·dwMilliseconds:指定以毫秒為單位的超時(shí)間隔。如果超時(shí),即使對(duì)象的狀態(tài)是非信號(hào)態(tài)的并且沒有完成,函數(shù)也返回。如果dwMilliseconds是0,函數(shù)測(cè)試對(duì)象的狀態(tài)并立即返回;如果dwMilliseconds是INFINITE,函數(shù)從不超時(shí)。返回值:
如果函數(shù)調(diào)用成功,返回值表明引起函數(shù)返回的事件。可能值如下:
·WAIT-ABANDONED:指定對(duì)象是互斥對(duì)象,在線程被終止前,線程沒有釋放互斥對(duì)象?;コ鈱?duì)象的所屬關(guān)系被授予調(diào)用線程,并且該互斥對(duì)象被置為非信號(hào)態(tài)。·WAIT-OBJECT-0:指定對(duì)象的狀態(tài)被置為信號(hào)態(tài)。
·WAIT-TIMEOUT:超時(shí),并且對(duì)象的狀態(tài)為非信號(hào)態(tài)。
如果函數(shù)調(diào)用失敗,返回值是WAIT-FAILED。若想獲得更多錯(cuò)誤信息,請(qǐng)調(diào)用GetLastError函數(shù)。
備注:
waitForSingleObjects函數(shù)決定等待條件是否被滿足。如果等待條件并沒有被滿足,調(diào)用線程進(jìn)入一個(gè)高效的等待狀態(tài),當(dāng)?shù)却凉M足條件時(shí)占用非常少的處理機(jī)時(shí)間。
在運(yùn)行前,一個(gè)等待函數(shù)修改同步對(duì)象類型的狀態(tài)。修改僅發(fā)生在引起函數(shù)返回的對(duì)象身上。例如,信號(hào)的計(jì)數(shù)減1。
WaitForSingleObjects函數(shù)能等待的對(duì)象包括:Change notification(改變通告);Consoleinput(控制臺(tái)輸入);Event(事件);Job(作業(yè));Mutex(互斥對(duì)象);Process(進(jìn)程);Semaphore(信號(hào)量);Thread(線程);Waitable timer(可等待定時(shí)器)。
當(dāng)使用等待函數(shù)或代碼直接或間接創(chuàng)建窗口時(shí),一定要小心。如果一個(gè)線程創(chuàng)建了任何窗口,它必須處理進(jìn)程消息。消息廣播被發(fā)送到系統(tǒng)的所有窗口。一個(gè)線程用沒有超時(shí)的等待函數(shù)也許會(huì)引起系統(tǒng)死鎖。間接創(chuàng)建窗口的兩個(gè)例子是DDE和COM CoInitialize。因此,如果用戶有一個(gè)創(chuàng)建窗口的線程,用MsgWaitForMultipleObjects或MsgWaitForMultipleObjectsEx函數(shù),而不要用SignalObjectAndWait函數(shù)。
7.WaitForMultipleObjects 函數(shù)功能:
WaitForMultipleObjects函數(shù)當(dāng)下列條件之一滿足時(shí)返回:(1)任意一個(gè)或全部指定對(duì)象處于信號(hào)態(tài);(2)超時(shí)間隔以過(guò)。
函數(shù)原型:
DWORD WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles, BOOL fWaitAll,DWORD dwMilliseconds);參數(shù):
·nCount:指定由lpHandles所指向的數(shù)組中的句柄對(duì)象數(shù)目MAXIMUM-WAIT-OBJECTS。
·lpHandles:指向?qū)ο缶浔鷶?shù)組的指針。該數(shù)組可以包含不同類型對(duì)象的句柄。在Windows NT中,句柄必須有SYNCHRONIZE訪問(wèn)權(quán)限。若想獲得更多的信息,請(qǐng)查看Standard Access Rights。
·fWaitall:指定等待類型。如果為TRUE,當(dāng)lpHandles指向的數(shù)組里的全部對(duì)象為信號(hào)態(tài)時(shí),函數(shù)返回。如果為FALSE,當(dāng)由lpHandles指向的數(shù)組里的任一對(duì)象為信號(hào)態(tài)時(shí),函數(shù)返回。對(duì)于后者,返回值指出引起函數(shù)返回的對(duì)象。
·dwMilliseconds:指定以毫秒為單位的超時(shí)間隔。如果超時(shí),即使bWaitAll參數(shù)指定的條件沒有滿足,函數(shù)也返回。如果dwMilliseconds是0,函數(shù)測(cè)試對(duì)象的狀態(tài)并立即返回;如果dwMilliseconds是INFINITE,函數(shù)從不超時(shí)。
返回值:
如果函數(shù)調(diào)用成功,返回值表明引起函數(shù)返回的事件??赡苤等缦拢?/p>
·WAIT-OBJECT-0到WAIT-OBJECT-0+nCount-1:如果bWaitAll為TRUE,那么返回值表明所有指定對(duì)象的狀態(tài)為信號(hào)態(tài)。如果bWaitAll為FALSE,那么返回值減去WAIT-OBJECT-0表明引起函數(shù)返回的對(duì)象的pHandles數(shù)組索引。如果多于一個(gè)對(duì)象變?yōu)樾盘?hào)態(tài),則返回的是數(shù)組索引最小的信號(hào)態(tài)對(duì)象索引。
·WAIT-ABANDONED-0到·WAIT-ABANDONED-0+ nCount-1:如果bWaitAll為TRUE,那么返回值表明所有指定對(duì)象的狀態(tài)為信號(hào)態(tài),并且至少一個(gè)對(duì)象是已放棄的互斥對(duì)象。如果bWaitAll為FALSE,那么返回值減去WAIT-OBJECT-0表明引起函數(shù)返回的放棄互斥對(duì)象的pHandles數(shù)組索引。
·WAIT-TIMEOUT:超時(shí)并且由參數(shù)bWaitAll指定的條件沒有滿足。
如果函數(shù)調(diào)用失敗,返回值是WAIT-FAILED。若想獲得更多錯(cuò)誤信息,請(qǐng)調(diào)用GetLastError函數(shù)。
8.CreateSemapore 函數(shù)功能:
該函數(shù)是創(chuàng)建一個(gè)有名或者無(wú)名信號(hào)對(duì)象。函數(shù)原型:
HANDLE CreateSwmaphore(LPSECURITY-ATTRIBUTES lpAttributes,LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);參數(shù):
·lpAttributes:安全屬性。如果是NULL就表示要使用默認(rèn)屬性。·lInitialCount:Semapore的初值。必須大于或等于0,并且小于或等于MaximumCount。·lMaximumCount:Semapore的最大值。這也就是在同一時(shí)間內(nèi)能夠鎖住Semapore之線程的最多個(gè)數(shù)。
·lpName:Semapore的名稱(一個(gè)字符串)。任何線程(或進(jìn)程)都可以根據(jù)這一名稱引用到這個(gè)Semaphore。這個(gè)值可以是NULL,意思是產(chǎn)生一個(gè)沒有名字的Semaphore。
返回值:
如果成功就傳回一個(gè)handle,否則傳回NULL。不論哪一種情況,GetLastError都會(huì)傳回一個(gè)合理的結(jié)果。如果指定的Semaphore名稱已經(jīng)存在,則該函數(shù)還是成功的,GetLastError會(huì)傳回ERROR_ALREADY_EXISTS。
9.ReleaseSemaphore 函數(shù)功能:
該函數(shù)將指定信號(hào)對(duì)象的計(jì)數(shù)增加一個(gè)指定的數(shù)量。函數(shù)原型:
BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount,LPLONG lpPreviousCount);參數(shù):
·hSemaphore:Semaphore的handle。
·lReleaseCount:Semaphore現(xiàn)值的增額。該值不可以是負(fù)值或0?!pPreviousCount:借此返回Semaphore原來(lái)的值。返回值:
如果成功,則返回TRUE。否則返回FALSE。失敗時(shí)可調(diào)用GetLastError獲得原因。備注:
無(wú)論ReleaseSemaphore對(duì)于Semaphore所造成的當(dāng)前值怎樣增加,都絕對(duì)不會(huì)超過(guò)CreateSemaphore時(shí)所指定的ImaximumCount。
請(qǐng)記住,lpPreviousCount所傳回來(lái)的是一個(gè)瞬間值。你不可以把lReleaseCount加上* lpPreviousCount,就當(dāng)做是Semaphore的當(dāng)前值,因?yàn)槠渌€程可能已經(jīng)改變了Semaphore的值。
與mutex不同的是,調(diào)用ReleaseSemaphore的那個(gè)線程,并不一定就是調(diào)用WaitXxx 的那個(gè)線程。任何線程都可以在任何時(shí)候調(diào)用ReleaseSemaphore,解除被任何線程鎖定的Semaphore。10.InitializeCriticalSection 函數(shù)功能:
該函數(shù)初始化臨界區(qū)對(duì)象。函數(shù)原型:
VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 參數(shù):
·lpCriticalSection:指向臨界區(qū)對(duì)象的指針。備注:
單進(jìn)程的所有線程可以使用互斥同步機(jī)制的臨界區(qū)對(duì)象。但是,不能保證線程獲得臨界區(qū)所有權(quán)的順序,系統(tǒng)將對(duì)所有線程公平處理。
進(jìn)程負(fù)責(zé)分配臨界區(qū)對(duì)象使用的存儲(chǔ)空間,這可以通過(guò)聲明CRITICAL_SECTION類型的變量來(lái)完成。在使用臨界區(qū)之前,該進(jìn)程的一些線程必須使用InitializeCriticalSection或InitializeCriticalSectionAndSectiom函數(shù)來(lái)初始化該臨界區(qū)對(duì)象。
11.EnterCriticalSection 函數(shù)功能:該函數(shù)是等待指定臨界區(qū)對(duì)象的所有權(quán)。當(dāng)調(diào)用線程被賦予所有權(quán)時(shí),該函數(shù)返回。
函數(shù)原型:
VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 參數(shù):
·lpCriticalSection:指向臨界區(qū)對(duì)象的指針。12.LeaveCriticalSection 函數(shù)功能:該函數(shù)釋放指定臨界區(qū)對(duì)象的所有權(quán)。函數(shù)原型:
VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 參數(shù):
·lpCriticalSection:指向臨界區(qū)對(duì)象的指針。4.1.5參考源代碼
下面的程序已經(jīng)在Windows 2000/XP上實(shí)現(xiàn)。用VC6.0創(chuàng)建源文件,將輸入文件命名為thread.dat并放在與源文件相同的文件夾內(nèi),編譯運(yùn)行即可(本節(jié)中的參考源代碼僅供參考)。
#include “windows.h” #include
#define READER 'R'
// 讀者 #define WRITER 'W'
// 寫者
#define INTE_PER_SEC 1000
// 每秒時(shí)鐘中斷數(shù)目。#define MAX_THREAD_NUM 64
// 最大線程數(shù)目 #define MAX_FILE_NUM 32
// 最大數(shù)據(jù)文件數(shù)目 #define MAX_STR_LEN 32
// 字符串長(zhǎng)度
int readcount=0;
// 讀者數(shù)目 int writecount=0;
// 寫者數(shù)目
CRITICAL_SECTION RP_Write;
//臨界區(qū) CRITICAL_SECTION cs_Write;CRITICAL_SECTION cs_Read;struct ThreadInfo { int
serial;
// 線程序號(hào)
char entity;
//線程類別(判斷讀者線程還是寫者線程)double delay;double persist;};
/////////////////////////////////////////////////////////////////////////// // 讀者優(yōu)先--讀者線程 //p:讀者線程信息
void RP_ReaderThread(void* p){
//互斥變量
HANDLE h_Mutex;h_Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,“mutex_for_readcount”);
DWORD wait_for_mutex;
//等待互斥變量所有權(quán) DWORD m_delay;
// 延遲時(shí)間
DWORD m_persist;
// 讀文件持續(xù)時(shí)間 int m_serial;
//線程序號(hào) //從參數(shù)中獲得信息
m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);Sleep(m_delay);
//延遲等待
printf(“Reader thread %d sents the reading require.n”,m_serial);
// 等待互斥信號(hào),保證對(duì)readcount的訪問(wèn)、修改互斥 wait_for_mutex=WaitForSingleObject(h_Mutex,-1);//讀者數(shù)目增加 readcount++;if(readcount==1){
//第一個(gè)讀者,等待資源
EnterCriticalSection(&RP_Write);} ReleaseMutex(h_Mutex);
//釋放互斥信號(hào)
//讀文件
printf(“Reader thread %d begins to read file.n”,m_serial);Sleep(m_persist);
// 退出線程
printf(“Reader thread %d finished reading file.n”,m_serial);//等待互斥信號(hào),保證對(duì)readcount的訪問(wèn)、修改互斥 wait_for_mutex=WaitForSingleObject(h_Mutex,-1);//讀者數(shù)目減少 readcount--;if(readcount==0){
//如果所有讀者讀完,喚醒寫者
LeaveCriticalSection(&RP_Write);} ReleaseMutex(h_Mutex);
//釋放互斥信號(hào) }
/////////////////////////////////////////////////////////////////////////// // 讀者優(yōu)先--寫者線程 //p:寫者線程信息
void RP_WriterThread(void* p){ DWORD m_delay;
// 延遲時(shí)間
DWORD m_persist;
// 寫文件持續(xù)時(shí)間 int m_serial;
//線程序號(hào) //從參數(shù)中獲得信息
m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);Sleep(m_delay);
//延遲等待
printf(“Writer thread %d sents the writing require.n”,m_serial);// 等待資源
EnterCriticalSection(&RP_Write);
//寫文件 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);//釋放資源
LeaveCriticalSection(&RP_Write);}
/////////////////////////////////////////////////////////////////////////// // 讀者優(yōu)先處理函數(shù) //file:文件名
void ReaderPriority(char* file){ DWORD n_thread=0;
//線程數(shù)目 DWORD thread_ID;
//線程ID DWORD wait_for_all;
//等待所有線程結(jié)束 //互斥對(duì)象
HANDLE h_Mutex;h_Mutex=CreateMutex(NULL,FALSE,“mutex_for_readcount”);
//線程對(duì)象的數(shù)組
HANDLE h_Thread[MAX_THREAD_NUM];ThreadInfo thread_info[MAX_THREAD_NUM];
readcount=0;
// 初始化 readcount
InitializeCriticalSection(&RP_Write);
//初始化臨界區(qū) ifstream inFile;inFile.open(file);
//打開文件 printf(“Reader Priority:nn”);while(inFile){
//讀入每一個(gè)讀者、寫者的信息
inFile>>thread_info[n_thread].serial;
inFile>>thread_info[n_thread].entity;
inFile>>thread_info[n_thread].delay;
inFile>>thread_info[n_thread++].persist;
inFile.get();} for(int i=0;i<(int)(n_thread);i++){
if(thread_info[i].entity==READER || thread_info[i].entity=='R')
{
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_ReaderThread),&thread_info[i],0,&thread_ID);//創(chuàng)建讀者線程
} else{
//創(chuàng)建寫者線程
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_WriterThread),&thread_info[i],0,&thread_ID);
} }
//等待所有線程結(jié)束
wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);printf(“All reader and writer have finished operating.n”);}
/////////////////////////////////////////////////////////////////////////// // 寫者優(yōu)先--讀者線程 //p:讀者線程信息
void WP_ReaderThread(void* p){
//互斥變量
HANDLE h_Mutex1;h_Mutex1=OpenMutex(MUTEX_ALL_ACCESS,FALSE,“mutex1”);HANDLE h_Mutex2;h_Mutex2=OpenMutex(MUTEX_ALL_ACCESS,FALSE,“mutex2”);
DWORD wait_for_mutex1;
//等待互斥變量所有權(quán) DWORD wait_for_mutex2;DWORD m_delay;
// 延遲時(shí)間
DWORD m_persist;
// 讀文件持續(xù)時(shí)間 int m_serial;
//線程序號(hào) //從參數(shù)中獲得信息
m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);Sleep(m_delay);
//延遲等待
printf(“Reader thread %d sents the reading require.n”,m_serial);wait_for_mutex1= WaitForSingleObject(h_Mutex1,-1);//進(jìn)入讀者臨界區(qū)
EnterCriticalSection(&cs_Read);// 阻塞互斥對(duì)象mutex2,保證對(duì)readcount的訪問(wèn)、修改互斥 wait_for_mutex2= WaitForSingleObject(h_Mutex2,-1);//修改讀者數(shù)目 readcount++;if(readcount==1){
//如果是第一個(gè)讀者,等待寫者寫完
EnterCriticalSection(&cs_Write);} ReleaseMutex(h_Mutex2);
//釋放互斥信號(hào)mutex2 // 讓其他讀者進(jìn)入臨界區(qū)
LeaveCriticalSection(&cs_Write);ReleaseMutex(h_Mutex1);//讀文件
printf(“Reader thread %d begins to read file.n”,m_serial);Sleep(m_persist);// 退出線程
printf(“Reader thread %d finished reading file.n”,m_serial);// 阻塞互斥對(duì)象mutex2,保證對(duì)readcount的訪問(wèn)、修改互斥 wait_for_mutex2= WaitForSingleObject(h_Mutex2,-1);readcount--;if(readcount==0){
// 最后一個(gè)讀者,喚醒寫者
LeaveCriticalSection(&cs_Write);} ReleaseMutex(h_Mutex2);
//釋放互斥信號(hào) } /////////////////////////////////////////////////////////////////////////// // 寫者優(yōu)先--寫者線程 //p:寫者線程信息
void WP_WriterThread(void* p){ DWORD m_delay;
// 延遲時(shí)間
DWORD m_persist;
// 寫文件持續(xù)時(shí)間 int m_serial;
//線程序號(hào) DWORD wait_for_mutex3;//互斥對(duì)象
HANDLE h_Mutex3;h_Mutex3= OpenMutex(MUTEX_ALL_ACCESS,FALSE,“mutex3”);
//從參數(shù)中獲得信息
m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);m_persist=(DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);Sleep(m_delay);
//延遲等待 printf(“Writer thread %d sents the writing require.n”,m_serial);
// 阻塞互斥對(duì)象mutex3,保證對(duì)writecount的訪問(wèn)、修改互斥 wait_for_mutex3= WaitForSingleObject(h_Mutex3,-1);writecount++;
//修改讀者數(shù)目 if(writecount==1){
//第一個(gè)寫者,等待讀者讀完
EnterCriticalSection(&cs_Read);} ReleaseMutex(h_Mutex3);
//進(jìn)入寫者臨界區(qū)
EnterCriticalSection(&cs_Write);//寫文件
printf(“Writer thread %d begins to Write to the file.n”,m_serial);Sleep(m_persist);
// 退出線程
printf(“Writer thread %d finishing Writing to the file.n”,m_serial);
//離開臨界區(qū)
LeaveCriticalSection(&cs_Write);
// 阻塞互斥對(duì)象mutex3,保證對(duì)writecount的訪問(wèn)、修改互斥 wait_for_mutex3= WaitForSingleObject(h_Mutex3,-1);writecount--;
//修改讀者數(shù)目 if(writecount==0){
//寫者寫完,讀者可以讀
LeaveCriticalSection(&cs_Read);} ReleaseMutex(h_Mutex3);}
/////////////////////////////////////////////////////////////////////////// // 寫者優(yōu)先處理函數(shù) //file:文件名
void WriterPriority(char* file){ DWORD n_thread=0;
//線程數(shù)目 DWORD thread_ID;
//線程ID DWORD wait_for_all;
//等待所有線程結(jié)束
//互斥對(duì)象
HANDLE h_Mutex1;h_Mutex1=CreateMutex(NULL,FALSE,“mutex1”);HANDLE h_Mutex2;h_Mutex2=CreateMutex(NULL,FALSE,“mutex2”);HANDLE h_Mutex3;h_Mutex3=CreateMutex(NULL,FALSE,“mutex3”);
//線程對(duì)象
HANDLE h_Thread[MAX_THREAD_NUM];ThreadInfo thread_info[MAX_THREAD_NUM];
readcount=0;
// 初始化 readcount writecount=0;
// 初始化writecount InitializeCriticalSection(&cs_Write);
//初始化臨界區(qū) InitializeCriticalSection(&cs_Read);ifstream inFile;inFile.open(file);
//打開文件 printf(“Writer Priority:nn”);while(inFile){
//讀入每一個(gè)讀者、寫者的信息
inFile>>thread_info[n_thread].serial;
inFile>>thread_info[n_thread].entity;
inFile>>thread_info[n_thread].delay;
inFile>>thread_info[n_thread++].persist;
inFile.get();} for(int i=0;i<(int)(n_thread);i++){
if(thread_info[i].entity==READER || thread_info[i].entity=='R')
{
//創(chuàng)建讀者線程
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_WriterThread),&thread_info[i],0,&thread_ID);
} else{
//創(chuàng)建寫者線程
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(WP_WriterThread),&thread_info[i],0,&thread_ID);
} }
//等待所有線程結(jié)束
wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);printf(“All reader and writer have finished operating.n”);} /////////////////////////////////////////////////////////////////////////////// //主函數(shù)
int main(int argc,char* argv[]){ char ch;
while(true){
//打印提示信息
printf(“************************************************n”);
printf(“
1:Reader Priorityn”);
printf(“
2:Writer Priorityn”);
printf(“
3:Exit Priorityn”);
printf(“************************************************n”);
printf(“Enter your choice(1,2 or 3): ”);
//如果輸入信息不正確,繼續(xù)輸入
do{
ch=(char)_getch();
}while(ch!= '1' &&ch!= '2' && ch!= '3');
system(“cls”);
//選擇3,返回
if(ch=='3')
return 0;
//選擇1,讀者優(yōu)先
else if(ch=='1')
ReaderPriority(“thread.dat”);
//選擇2,寫者優(yōu)先
else if(ch=='2')
WriterPriority(“thread.dat”);
//結(jié)束
printf(“nPress Any Key To Continue: ”);
_getch();
system(“cls”);} return 0;}
說(shuō)明:
在Win32 API中,互斥對(duì)象Mutex與P、V中的互斥信號(hào)量有類似的地方,但也有不同:在P、V操作中的互斥信號(hào)量可以有一個(gè)任意大小的初值,但互斥對(duì)象Mutex沒有,它可以被看成是初值為1的互斥信號(hào)量。而且一個(gè)線程在取得Mutex的所有權(quán)之后,即使不調(diào)用ReleaseMutex函數(shù),在線程結(jié)束時(shí),線程也會(huì)自動(dòng)釋放Mutex的所有權(quán)。
臨界區(qū)對(duì)象CriticalSection則與P、V操作中初值為1的互斥信號(hào)量語(yǔ)意相同。它在線程結(jié)束時(shí)會(huì)將CriticalSection的所有權(quán)傳遞給它的同類型線程。這樣就可以滿足在一個(gè)線程中申請(qǐng)所有權(quán),在另一個(gè)線程釋放所有權(quán)的要求。在讀者優(yōu)先中的write互斥信號(hào)量以及寫者優(yōu)先中的read和write互斥信號(hào)量就應(yīng)該用CriticalSection實(shí)現(xiàn)而不應(yīng)該用Mutex。
用WaitForSingleSignal函數(shù)可以獲得一個(gè)Mutex的所有權(quán),類似于P操作,而ReleaseMutex函數(shù)可以釋放一個(gè)Mutex的所有權(quán),類似于V操作。
用EnterCriticalSection函數(shù)可以進(jìn)入一個(gè)CriticalSection,類似于P操作,而LeaveCriticalSection函數(shù)離開一個(gè)CriticalSection,類似于V操作。
備注:
ReaderPriority和WritePriority函數(shù)最后都有
wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);是因?yàn)橹骱瘮?shù)要等待所有的線程都結(jié)束之后才退出。因?yàn)椴恢烙卸嗌倬€程,所以源文件最初有:
#define MAX_THREAD_NUM 64 //最大線程數(shù)目
即線程最多不能超過(guò)MAX_THREAD_NUM個(gè)。線程對(duì)象的數(shù)組大小為MAX_THREAD_NUM。如果創(chuàng)建的線程沒有那么多,空間會(huì)有浪費(fèi),但是可以達(dá)到犧牲空間來(lái)節(jié)省時(shí)間的目的。
有的書上還有其他的處理方法。一種是在主函數(shù)的最后加上Sleep(1000),即通過(guò)主函數(shù)睡眠的方法等待其他線程結(jié)束,這當(dāng)然不是一種很好的方法,因?yàn)樗叩却臅r(shí)間沒法控制。另一種方法是增加循環(huán)變量threadCount(線程的個(gè)數(shù)),每個(gè)線程結(jié)束的就會(huì)執(zhí)行語(yǔ)句
threadCount--;主函數(shù)的最后測(cè)試:
while(threadcount>0);但是這種方式會(huì)讓主函數(shù)循環(huán)等待,浪費(fèi)了CPU資源。
相比之下,考慮到運(yùn)行效率,還是實(shí)例中給出的方法比較好寫些。
第四篇:操作系統(tǒng)課程設(shè)計(jì)報(bào)告
課程設(shè)計(jì)報(bào)告
題 目: 模擬請(qǐng)求頁(yè)式管理
課程名稱: 計(jì)算機(jī)操作系統(tǒng) 學(xué) 院: 信息工程學(xué)院
專 業(yè): 計(jì)算機(jī)科學(xué)與技術(shù)
班 級(jí): 14計(jì)本(1)學(xué)生姓名: * * * 學(xué) 號(hào): 201403031** 指導(dǎo)教師: * * 成 績(jī):
開課時(shí)間: 2016-2017 學(xué)年 一 學(xué)期
模擬請(qǐng)求頁(yè)式管理
第1章 需求分析
1.1設(shè)計(jì)要求
請(qǐng)求頁(yè)式管理是一種常用的虛擬存儲(chǔ)管理技術(shù)。本設(shè)計(jì)通過(guò)請(qǐng)求頁(yè)式存儲(chǔ)管理中頁(yè)面置換算法模擬設(shè)計(jì),了解虛擬存儲(chǔ)技術(shù)的特點(diǎn),掌握請(qǐng)求頁(yè)式管理的頁(yè)面置換算法。本實(shí)驗(yàn)要求用Vc++或其他高級(jí)語(yǔ)言編寫和調(diào)試。
編寫程序?qū)崿F(xiàn):
(1)先進(jìn)先出頁(yè)面置換算法(FIFO)(2)最近最久未使用頁(yè)面置換算法(LRU)最佳置換頁(yè)面置換算法(OPT)設(shè)計(jì)一個(gè)虛擬存儲(chǔ)區(qū)和內(nèi)存工作區(qū),編程序演示以上三種算法的具體實(shí)現(xiàn)過(guò)程,并計(jì)算訪問(wèn)命中率。
1.2解決方案
首先確定實(shí)現(xiàn)語(yǔ)言使用c#實(shí)現(xiàn)圖形化界面,后確定要實(shí)現(xiàn)哪些功能,比如算法選擇,頁(yè)面添加,模擬控制。然后確定輸出結(jié)構(gòu)以便于程序的測(cè)試和驗(yàn)證。將基本框架建立后再進(jìn)行編程。編程前進(jìn)行算法結(jié)構(gòu)分析最后編程實(shí)現(xiàn)。
1.3算法實(shí)現(xiàn)原理
1、先進(jìn)先出置換算法(FIFO):
發(fā)生缺頁(yè)中斷時(shí)按照頁(yè)面進(jìn)入內(nèi)存順序總是淘汰最先進(jìn)入內(nèi)存的頁(yè)面。
2、最近最久未使用置換算法(LRU):
發(fā)生缺頁(yè)中斷時(shí)總是淘汰存在內(nèi)存中最長(zhǎng)時(shí)間未被使用的頁(yè)面。
3、最佳置換算法(OPT):
發(fā)生缺頁(yè)中斷時(shí)若一個(gè)或幾個(gè)頁(yè)面將來(lái)將不會(huì)被調(diào)用則按先進(jìn)先出原則淘汰頁(yè)面,若將來(lái)都有調(diào)用則比較調(diào)用時(shí)刻選擇最遠(yuǎn)時(shí)刻頁(yè)面淘汰。
4、缺頁(yè)率:缺頁(yè)次數(shù)占頁(yè)面調(diào)用次數(shù)的百分比。
第2章 概要設(shè)計(jì)
2.1數(shù)據(jù)設(shè)計(jì)
常變量:調(diào)用頁(yè)面最大數(shù)量(MaxN),內(nèi)存最大頁(yè)面數(shù)(MaxM)待調(diào)用頁(yè)面數(shù)組:page_dd[MaxN]存放等待調(diào)用的頁(yè)面號(hào)
頁(yè)面數(shù)組專用指針 page_p,用于指向page_dd數(shù)組中正需調(diào)入內(nèi)存的頁(yè)號(hào) 內(nèi)存塊數(shù)組:Memery[MaxM],存放內(nèi)存當(dāng)前存放的頁(yè)號(hào) 缺頁(yè)計(jì)數(shù)器:count,記錄缺頁(yè)次數(shù)
內(nèi)存塊狀態(tài)數(shù)組:M1[MaxN],M2[MaxN],M3[MaxN],記錄每次頁(yè)面調(diào)用結(jié)束后內(nèi)存各塊的狀態(tài)
缺頁(yè)記錄數(shù)組s[MaxN],用于記錄頁(yè)面調(diào)用時(shí)是否產(chǎn)生缺頁(yè)中斷,初始化為是
2.2函數(shù)設(shè)計(jì)
1、頁(yè)面添加函數(shù):void btnAdd_Click(object sender, EventArgs e)用于實(shí)現(xiàn)通過(guò)點(diǎn)擊按鈕實(shí)現(xiàn)數(shù)據(jù)輸入。
2、內(nèi)存初始化函數(shù):init(int[] a, int[] b,int []m1,int[]m2,int[]m3)參數(shù)有頁(yè)面數(shù)組、內(nèi)存數(shù)組、狀態(tài)數(shù)組,采用先進(jìn)先出算法對(duì)內(nèi)存先進(jìn)行裝滿 服務(wù)于先進(jìn)先出頁(yè)面置換函數(shù)和最佳置換函數(shù)。
3、輸出函數(shù):void display(int[]a,int[]m1,int[]m2,int[]m3,char[]c)用于輸出模擬結(jié)果,參數(shù)有頁(yè)面數(shù)組,內(nèi)存數(shù)組,狀態(tài)數(shù)組,缺頁(yè)記錄數(shù)組。再模擬之后調(diào)用。
4、模擬控制函數(shù):void btnmo_Click(object sender, EventArgs e)用于實(shí)現(xiàn)通過(guò)單擊模擬按鈕,根據(jù)用戶所選算法進(jìn)行模擬并顯示結(jié)果。
5、先進(jìn)先出算法模擬函數(shù):
void FIFO(int[] a, int[] b,int[]m1,int[]m2,int[]m3,char[] s)用于實(shí)現(xiàn)先進(jìn)先出算法模擬,參數(shù)有頁(yè)面數(shù)組,內(nèi)存數(shù)組、內(nèi)存狀態(tài)記錄數(shù)組,缺頁(yè)記錄數(shù)組。在模擬函數(shù)中調(diào)用。
6、最近最久未使用算法模擬函數(shù):
void LRU(int[] a, int[] b, int[] m1, int[] m2, int[] m3, char[] s)用于 3 實(shí)現(xiàn)最近最久未使用算法模擬,參數(shù)有頁(yè)面數(shù)組,內(nèi)存數(shù)組,內(nèi)存狀態(tài)記錄數(shù)組,缺頁(yè)記錄數(shù)組。在模擬函數(shù)中被調(diào)用。
7、最近最久未使用函數(shù)輔助函數(shù):void LUR_I(int[] a,int e)用于對(duì)最近最久未使用算法中所用輔助數(shù)組(記錄頁(yè)面存在時(shí)長(zhǎng))進(jìn)行調(diào)整,參數(shù)有輔助數(shù)組及需調(diào)整的數(shù)據(jù)下標(biāo)。在最近最久未使用函數(shù)中調(diào)用。
8、最佳置換算法模擬函數(shù):
void OPT(int[] a, int[] b, int[] m1, int[] m2, int[] m3, char[] s)用于模擬最佳置換算法。參數(shù)有頁(yè)面數(shù)組,內(nèi)存數(shù)組,內(nèi)存狀態(tài)記錄數(shù)組,缺頁(yè)記錄數(shù)組。在模擬函數(shù)中被調(diào)用。
9、最佳置換算法輔助函數(shù):void OPT_F(int[] a, int e)用于對(duì)最佳置換算法中的輔助數(shù)組進(jìn)行調(diào)整。參數(shù)有輔助數(shù)組,需調(diào)整數(shù)據(jù)下標(biāo)。在最佳置換算法中被調(diào)用。
10、重置函數(shù):void btncz_Click(object sender, EventArgs e)用于重新選擇算法進(jìn)行新的模擬。
2.3主要算法設(shè)計(jì)
1、初始化函數(shù)算法:
第一步:將第一個(gè)頁(yè)面調(diào)入內(nèi)存,調(diào)整最佳置換算法輔助數(shù)組,缺頁(yè)計(jì)數(shù)器加一,保存內(nèi)存數(shù)組狀態(tài)。
第二步:調(diào)用下一個(gè)頁(yè)面并判斷內(nèi)存中是否有本頁(yè)面有轉(zhuǎn)第三步,無(wú)轉(zhuǎn)第四步。第三步:更改缺頁(yè)數(shù)組對(duì)應(yīng)下標(biāo)值,記錄當(dāng)前內(nèi)存狀態(tài),調(diào)整最佳置換算法輔助數(shù)組,頁(yè)面指針指向下一頁(yè)。
第四步:將頁(yè)面調(diào)入內(nèi)存,調(diào)整最佳置換算法輔助函數(shù),缺頁(yè)計(jì)數(shù)器加一,保存內(nèi)存數(shù)組狀態(tài)。若內(nèi)存尚不滿轉(zhuǎn)第一步。具體見圖1初始化算法流程圖。
開始頁(yè)面調(diào)入內(nèi)存缺頁(yè)計(jì)數(shù)器加一記錄內(nèi)存狀態(tài)調(diào)用下一頁(yè)否否內(nèi)存是否有該頁(yè)面是記錄內(nèi)存狀態(tài)修改缺頁(yè)數(shù)組內(nèi)存已滿是結(jié)束
圖1 初始化算法流程圖
2、先進(jìn)先出頁(yè)面置換算法:
第一步:檢查內(nèi)存中是否已有需調(diào)用頁(yè)面,有則轉(zhuǎn)第二步,無(wú)則轉(zhuǎn)第三步。第二步:記錄當(dāng)前內(nèi)存狀態(tài),修改缺頁(yè)數(shù)組對(duì)應(yīng)下標(biāo)值。
第三步:內(nèi)存中無(wú)需要調(diào)用的頁(yè)面,進(jìn)行出隊(duì)操作,然后進(jìn)行入隊(duì)操作,記錄內(nèi)存塊狀態(tài),缺頁(yè)計(jì)數(shù)器加一。
第四步:若頁(yè)面數(shù)組未被調(diào)用結(jié)束轉(zhuǎn)第一步。具體見圖2先進(jìn)先出算法流程圖。
開始頁(yè)面調(diào)入內(nèi)存該頁(yè)在內(nèi)存中是否已存在是否否先出隊(duì)操作后入隊(duì)操作記錄內(nèi)存狀態(tài)修改缺頁(yè)數(shù)組值記錄內(nèi)存狀態(tài)缺頁(yè)計(jì)數(shù)器加一頁(yè)面調(diào)用結(jié)束是結(jié)束
圖2 先進(jìn)先出算法流程圖
3、最近最久未使用置換算法:
第一步:將頁(yè)面調(diào)入內(nèi)存,記錄內(nèi)存狀態(tài),缺頁(yè)計(jì)數(shù)器加一,調(diào)整輔助數(shù)組,頁(yè)面指針加一。
第二步:檢查內(nèi)存中是否已有所需頁(yè)面,有轉(zhuǎn)第三步,無(wú)轉(zhuǎn)第一步。
第三步:修改缺頁(yè)數(shù)組對(duì)應(yīng)下標(biāo)記錄,記錄內(nèi)存狀態(tài),調(diào)整輔助數(shù)組,頁(yè)面指針加一。第四步:內(nèi)存是否已滿,無(wú)則轉(zhuǎn)第一步,是則轉(zhuǎn)第五步。
第五步:檢查內(nèi)存中是否有所需頁(yè)面,有則記錄當(dāng)前內(nèi)存狀態(tài),修改缺頁(yè)數(shù)組對(duì)應(yīng)下標(biāo)值。無(wú)則轉(zhuǎn)第六步。
第六步:檢查輔助數(shù)組找出最大值并記錄其下標(biāo),置換內(nèi)存中對(duì)應(yīng)下標(biāo)的數(shù)據(jù),調(diào)整輔助數(shù)組,缺頁(yè)計(jì)數(shù)器加一。
第七步:頁(yè)面是否調(diào)用結(jié)束未結(jié)束則轉(zhuǎn)第五步。具體見圖3最近最久未使用算法流程圖。
開始調(diào)入頁(yè)面至內(nèi)存記錄內(nèi)存狀態(tài)計(jì)數(shù)器加一否調(diào)整輔助數(shù)組調(diào)用下一頁(yè)內(nèi)存中是否已有該頁(yè)否內(nèi)存已滿是通過(guò)輔助數(shù)組確定淘汰頁(yè)面是修改缺頁(yè)數(shù)組記錄內(nèi)存狀態(tài)調(diào)整輔助數(shù)組否頁(yè)面置換記錄內(nèi)存狀態(tài)計(jì)數(shù)器加一調(diào)用結(jié)束是結(jié)束
圖3 最近最久未使用算法
4、最佳置換算法:
第一步:檢查內(nèi)存中是否已有所需頁(yè)面,有則記錄內(nèi)存狀態(tài),修改缺頁(yè)數(shù)組對(duì)應(yīng)下標(biāo)數(shù)值。無(wú)則轉(zhuǎn)第二步。
第二步:判斷內(nèi)存中各頁(yè)面的未來(lái)調(diào)用情況,記錄是否還有調(diào)用,若有則記錄調(diào)用時(shí)刻。
第三步:分析調(diào)用情況,內(nèi)存中頁(yè)面都在將來(lái)不會(huì)被調(diào)用轉(zhuǎn)第四步,有一個(gè)被調(diào)用轉(zhuǎn)第五步,有兩個(gè)被調(diào)用轉(zhuǎn)第六步,全被調(diào)用轉(zhuǎn)第七步。
第四步:查找輔助數(shù)組找到內(nèi)存中存在時(shí)間最長(zhǎng)的頁(yè)面進(jìn)行置換,修改內(nèi)存狀態(tài),缺頁(yè)計(jì)數(shù)器加一,修改輔助數(shù)組。
第五步:查找到不會(huì)被調(diào)用的頁(yè)面,并根據(jù)輔助數(shù)組選擇最早進(jìn)入內(nèi)存的頁(yè)面將其置換。修改內(nèi)存狀態(tài),缺頁(yè)計(jì)數(shù)器加一,修改輔助數(shù)組。
第六步:查找輔助數(shù)組找到將來(lái)不需要在調(diào)用的頁(yè)面將其置換,修改輔助數(shù)組,記錄內(nèi)存狀態(tài),缺頁(yè)計(jì)數(shù)器加一。
第七步:查找輔助數(shù)組,找尋最晚被調(diào)用的頁(yè)面,將其置換。記錄內(nèi)存狀態(tài),修改輔助數(shù)組,缺頁(yè)計(jì)數(shù)器加一。
第八步:頁(yè)面是否調(diào)用完成,否則轉(zhuǎn)第一步。具體見圖4最佳置換算法流程圖
開始調(diào)入頁(yè)面記錄內(nèi)存狀態(tài)計(jì)數(shù)器加一更新輔助函數(shù)是頁(yè)面已存在否向后檢查內(nèi)存當(dāng)前頁(yè)面調(diào)用情況所有頁(yè)面都不會(huì)再度調(diào)用否是一個(gè)頁(yè)面會(huì)調(diào)用否否是兩個(gè)頁(yè)面會(huì)調(diào)用是否查找輔助數(shù)組得到最先進(jìn)入頁(yè)面通過(guò)輔助數(shù)組得到不會(huì)再調(diào)用的頁(yè)面通過(guò)輔助數(shù)組獲取最晚調(diào)用的頁(yè)面通過(guò)輔助數(shù)組得到另外兩個(gè)頁(yè)面中最先進(jìn)入的頁(yè)面置換頁(yè)面記錄內(nèi)存狀態(tài)計(jì)數(shù)器加一更新輔助函數(shù)頁(yè)面調(diào)用結(jié)束是結(jié)束
圖4 最佳置換算法流程圖 2.4界面設(shè)計(jì)
采用c# 設(shè)計(jì)windows窗體應(yīng)用程序,使用下拉列表框選擇算法,通過(guò)按鈕添加待調(diào)用的頁(yè)面。通過(guò)文本控件顯示模擬結(jié)果。顯示樣式:第一行:算法名稱;
第二行:調(diào)用頁(yè)面順序;
第三行至第五行顯示內(nèi)存在每調(diào)用一次頁(yè)面后的狀態(tài);
第六行:是否缺頁(yè);
最后一行顯示缺頁(yè)率;
第3章 詳細(xì)設(shè)計(jì)與實(shí)現(xiàn)
3.1函數(shù)設(shè)計(jì)
1、添加按鈕功能實(shí)現(xiàn)代碼
主要功能:實(shí)現(xiàn)單擊一次添加一個(gè)調(diào)用頁(yè)面,并給出相應(yīng)的提示,如正在輸入的是第幾次調(diào)度頁(yè)面,在輸入為空時(shí)能夠彈出對(duì)話框提示用戶,在輸入完成時(shí)為避免數(shù)組越界應(yīng)在輸入完成時(shí)隱藏;輸入過(guò)程中始終保證時(shí)輸入焦點(diǎn)。private void btnAdd_Click(object sender, EventArgs e){ if(txtAdd.Text!= “")//輸入不為空才能繼續(xù)輸入 { page_dd[i_add] = Convert.ToInt32(txtAdd.Text);/*將輸入值賦值給頁(yè)面數(shù)組*/ txtShow.Text += txtAdd.Text + ” “;/*顯示供用戶查閱*/ i_add++;txtAdd.Clear();/*清空*/ if(i_add == MaxN)//輸入結(jié)束時(shí) { txtAdd.ReadOnly = true;//不允許繼續(xù)輸入 btnAdd.Hide();//按鈕隱藏 return;} txtAdd.Focus();//設(shè)置為輸入焦點(diǎn)
label2.Text = ”第“ +(i_add + 1)+ ”次調(diào)度頁(yè)面:“;/*提示用戶正在輸入的是第幾次調(diào)度頁(yè)面*/ } /*輸入為空則彈出對(duì)話框提示用戶輸入為空*/ else { MessageBox.Show(”請(qǐng)輸入調(diào)用頁(yè)面!“, ”輸入為空“, MessageBoxButtons.OK, MessageBoxIcon.Warning);txtAdd.Focus();} }
2、初始化函數(shù)
主要功能:將內(nèi)存一先進(jìn)先出方式填滿,并記錄每個(gè)頁(yè)面進(jìn)入時(shí)間,服務(wù)于先進(jìn)先出頁(yè)面置換算法和最佳置換算法。
void init(int[] a, int[] b,int []m1,int[]m2,int[]m3){ /*內(nèi)存未滿時(shí)循環(huán)*/ for(int i = 0;i < MaxM&&page_p //調(diào)整輔助數(shù)組將剛進(jìn)入內(nèi)存的頁(yè)面的對(duì)應(yīng)時(shí)間 OPT_F(O_Q ,i); count++;//缺頁(yè)計(jì)數(shù)器加一 m1[page_p] = b[0];//保存內(nèi)存狀態(tài) m2[page_p] = b[1];m3[page_p] = b[2];page_p++;//調(diào)用下一頁(yè)面 //檢查內(nèi)存中是否原先就有需要的頁(yè)面; for(int j = 0;j <= i&&page_p s[page_p] = 'F';//缺頁(yè)數(shù)組對(duì)應(yīng)數(shù)據(jù)更改 m1[page_p] = b[0];//記錄內(nèi)存狀態(tài) m2[page_p] = b[1];m3[page_p] = b[2];OPT_F(O_Q,-1);//調(diào)整最佳置換算法輔助函數(shù) page_p++;//調(diào)用下一頁(yè) j =-1;//重新開始尋找 } } } } 3、先進(jìn)先出頁(yè)面置換函數(shù) 主要功能:根據(jù)先進(jìn)先出算法要求在產(chǎn)生缺頁(yè)中斷時(shí)采用先進(jìn)先出方式確定淘汰頁(yè)面,并在每次頁(yè)面調(diào)用時(shí)記錄下內(nèi)存狀態(tài),缺頁(yè)次數(shù);采用循環(huán)隊(duì)列使得每次出隊(duì)的一定是最先進(jìn)入內(nèi)存的。 private void FIFO(int[] a, int[] b,int[]m1,int[]m2,int[]m3,char[] s){ int Fpage_p = page_p;int front, rear;//定義隊(duì)列對(duì)手和對(duì)尾指針并初始化 front = 0;rear = MaxM1;int sa;for(;Fpage_p < MaxN;Fpage_p++){ sa = 0;for(int i = 0;i < MaxM;i++)//檢查內(nèi)存中是否已有要調(diào)用的頁(yè)面。 { if(b[i] == a[Fpage_p]){ m1[Fpage_p] = b[0];m2[Fpage_p] = b[1];m3[Fpage_p] = b[2];s[Fpage_p] = 'F';sa = 1;break;} } if(sa == 0){ front =(front + 1)% MaxM; rear =(rear + 1)% MaxM;b[rear] = a[Fpage_p];m1[Fpage_p] = b[0];m2[Fpage_p] = b[1];m3[Fpage_p] = b[2];count++;} else continue;} } /*最近最久未使用算法輔助數(shù)組調(diào)整函數(shù)*/ private void LUR_I(int[] a,int e){ int temp;temp = a[e];a[e] = 1;for(int i = 0;i < MaxM;i++){ if(a[i] < temp && i!=e)a[i]++;} } /*最佳置換算法輔助數(shù)組調(diào)整函數(shù)*/ private void OPT_F(int[] a, int e){ if(e!=-1){ a[e] = 0;for(int i = 0;i < MaxM;i++){ if(i!= e)a[i]++;} } else for(int i = 0;i < MaxM;i++){ a[i]++;} } /*最近最久未使用算法*/ private void LRU(int[] a, int[] b, int[] m1, int[] m2, int[] m3, char[] s){ int[] L_Q = new int[MaxM]{3,3,3};int sa;for(int i = 0;i < MaxM && page_p < MaxN;i++){ b[i] = a[page_p];//調(diào)入內(nèi)存 count++;m1[page_p] = b[0];//保存內(nèi)存狀態(tài) m2[page_p] = b[1];m3[page_p] = b[2];LUR_I(L_Q, i);page_p++;for(int j = 0;j <= i && page_p < MaxN;j++){ if(b[j] == a[page_p]){ s[page_p] = 'F';m1[page_p] = b[0];m2[page_p] = b[1];m3[page_p] = b[2];LUR_I(L_Q, j);page_p++;j =-1;} } } for(;page_p < MaxN;page_p++){ sa = 0;for(int i = 0;i < MaxM;i++)//用的頁(yè)面。{ if(b[i] == a[page_p]){ m1[page_p] = b[0];m2[page_p] = b[1];m3[page_p] = b[2];s[page_p] = 'F';LUR_I(L_Q, i);sa = 1;break;} } if(sa == 0){ 檢查內(nèi)存中是否已有要調(diào)40 for(int i = 0;i < MaxM;i++){ if(L_Q[i] == 3){ b[i] = a[page_p];m1[page_p] = b[0];m2[page_p] = b[1];m3[page_p] = b[2];LUR_I(L_Q, i);break;} } count++;} else continue;} } /*最佳置換算法*/ private void OPT(int[] a, int[] b, int[] m1, int[] m2, int[] m3, char[] s){ int sa;int O_p;int Ocount;int[] OPT_I=new int [MaxM ]{-1 ,-1 ,-1 };int[] OPT_J=new int [MaxM]{MaxN ,MaxN ,MaxN };for(;page_p < MaxN;page_p++){ for(int i = 0;i < MaxM;i++){ OPT_I[i] =-1;//刷新狀態(tài)數(shù)組 OPT_J[i] = MaxN;} sa = 0;for(int i = 0;i < MaxM;i++)//檢查內(nèi)存中是否已有要調(diào)用的頁(yè)面。 { if(b[i] == a[page_p]){ m1[page_p] = b[0];m2[page_p] = b[1];m3[page_p] = b[2];OPT_F(O_Q,-1); s[page_p] = 'F';sa = 1;break;} } if(sa == 0)//缺頁(yè) { Ocount = 0;for(int i = 0;i < MaxM;i++){ O_p = page_p + 1;for(;O_p < MaxN;O_p++){ if(b[i] == a[O_p]){ Ocount++;OPT_I[i] = 1;OPT_J[i] = O_p;break;} } } switch(Ocount){ case 0://全部頁(yè)面以后都不會(huì)再度調(diào)用 int temp = 0;for(int i = 0;i < MaxM;i++){ if(O_Q[i] > O_Q[temp])temp = i;} b[temp] = a[page_p];m1[page_p] = b[0];m2[page_p] = b[1];m3[page_p] = b[2];OPT_F(O_Q ,temp);count++;break;case 1://有一個(gè)頁(yè)面將在以后調(diào)用 temp = 0;for(int i = 0;i < MaxM;i++){ if(OPT_I[i]!= 1 && O_Q[i] > O_Q[temp])temp = i; } b[temp] = a[page_p];m1[page_p] = b[0];m2[page_p] = b[1];m3[page_p] = b[2];OPT_F(O_Q ,temp);count++;break;case 2: for(int i = 0;i < MaxM;i++){ if(OPT_I[i] ==-1){ b[i] = a[page_p];m1[page_p] = b[0];m2[page_p] = b[1];m3[page_p] = b[2];OPT_F(O_Q, i);count++;} } break;case 3: int p = 0;for(int i = 0;i < MaxM;i++){ if(OPT_J[i] >OPT_J[p])p = i;} b[p] = a[page_p];m1[page_p] = b[0];m2[page_p] = b[1];m3[page_p] = b[2];OPT_F(O_Q, p);count++;break;} } } } /*重置函數(shù)*/ private void btncz_Click(object sender, EventArgs e){ comboBox1.SelectedIndex = 0; txtAdd.Text = ”“;page_p = 0;i_add = 0;count = 0;//txtShow.Text = ”";for(int i = 0;i < MaxM;i++)Memery[i] =-1;for(int i = 0;i < MaxN;i++)s[i] = 'T';} } } 操 作 系 統(tǒng) 課 程 設(shè) 計(jì) 實(shí) 驗(yàn) 報(bào) 告 學(xué)院:計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院 班級(jí):計(jì)112 學(xué)號(hào):1113022032 姓名: 一、實(shí)驗(yàn)名稱: 用C++實(shí)現(xiàn)驅(qū)動(dòng)調(diào)度算法、頁(yè)面替換算法、銀行家算法、處理器調(diào)度算法 二、實(shí)驗(yàn)要求: 書寫實(shí)驗(yàn)報(bào)告,包括的內(nèi)容有: (1)實(shí)驗(yàn)題目 (2)程序中使用的數(shù)據(jù)結(jié)構(gòu)及主要文字說(shuō)明 (3)帶有注釋的源程序 (4)執(zhí)行程序說(shuō)明,表明各進(jìn)程控制快的初始狀態(tài),以及各算法的運(yùn)行狀態(tài) (5)通過(guò)實(shí)驗(yàn)后的收獲與體會(huì)及對(duì)實(shí)驗(yàn)的改進(jìn)意見和見解 二、實(shí)驗(yàn)?zāi)康模?/p> 通過(guò)自己編程來(lái)實(shí)現(xiàn)各類操作系統(tǒng)算法,進(jìn)一步理解操作系統(tǒng)的概念及含義,提高對(duì)操作系統(tǒng)的認(rèn)識(shí),同時(shí)提高自己的動(dòng)手實(shí)踐能力。加強(qiáng)我們對(duì)各類算法的理解。 三、實(shí)驗(yàn)內(nèi)容: 1、實(shí)現(xiàn)頁(yè)面替換算法 (1)FIFO 先進(jìn)先出頁(yè)面替換算法 (2)LRU最近最少使用頁(yè)面替換算法 (3)LFU最少使用頻率頁(yè)面替換算法 2、銀行家算法 3、實(shí)現(xiàn)驅(qū)動(dòng)調(diào)度算法 (1)先來(lái)先服務(wù)算法 (2)電梯算法 (3)掃描算法 4、實(shí)現(xiàn)處理器調(diào)度 (1)先進(jìn)先出處理器調(diào)度 (2)時(shí)間片輪轉(zhuǎn)法 (3)優(yōu)先級(jí)調(diào)度 四、實(shí)驗(yàn)原理: 1、頁(yè)面替換算法 先進(jìn)先出頁(yè)面置換算法:該算法總是淘汰最先進(jìn)入內(nèi)存的頁(yè)面,即選擇在內(nèi)存中駐留時(shí)間最久的頁(yè)面加以淘汰。將已調(diào)入內(nèi)存的頁(yè)面按先后次序鏈接成一個(gè)隊(duì)列,將最先調(diào)入的頁(yè)面與新頁(yè)面進(jìn)行置換 最近最久未使用置換算法:該算法是利用“最近的過(guò)去”作為“最近的將來(lái)”,將最近最久未使用的頁(yè)面加以淘汰。將已調(diào)入內(nèi)存的頁(yè)面按先后順序鏈接成一個(gè)隊(duì)列,為每一個(gè)頁(yè)面增加一個(gè)訪問(wèn)字段,用來(lái)記錄一個(gè)頁(yè)面自上次被訪問(wèn)以來(lái)所經(jīng)歷的是時(shí)間t,當(dāng)需淘汰一個(gè)頁(yè)面時(shí),選擇現(xiàn)有頁(yè)面中其t值最大,即最近最久未使用的頁(yè)面加以淘汰 2、銀行家算法 先對(duì)用戶提出的請(qǐng)求進(jìn)行合法性檢查,即檢查請(qǐng)求的是不大于需要的,是否不大于可利用的。若請(qǐng)求合法,則進(jìn)行試分配。最后對(duì)試分配后的狀態(tài)調(diào)用安全性檢查算法進(jìn)行安全性檢查。若安全,則分配,否則,不分配,恢復(fù)原來(lái)狀態(tài),拒絕申請(qǐng)。 3、驅(qū)動(dòng)調(diào)度算法 先進(jìn)先出算法(FIFO):總是嚴(yán)格按時(shí)間順序?qū)Υ疟P請(qǐng)求予以處理。算法實(shí)現(xiàn)簡(jiǎn)單、易于理解并且相對(duì)公平,不會(huì)發(fā)生進(jìn)程餓死現(xiàn)象。但該算法可能會(huì)移動(dòng)的柱面數(shù)較多并且會(huì) 經(jīng)常更換移動(dòng)方向,效率有待提高 電梯調(diào)度算法:總是將一個(gè)方向上的請(qǐng)求全部處理完后,才改變方向繼續(xù)處理其他請(qǐng)求。 掃描算法(scan algorithm):總是從最外向最內(nèi)(或最內(nèi)向最外)進(jìn)行掃描,然后在從最內(nèi)向最外(或最外向最內(nèi))掃描。該算法與電梯調(diào)度算法的區(qū)別是電梯調(diào)度在沒有最外或最內(nèi)的請(qǐng)求時(shí)不會(huì)移動(dòng)到最外或最內(nèi)柱面。 4、處理器調(diào)度算法 先進(jìn)先出處理器調(diào)度:按照作業(yè)進(jìn)入系統(tǒng)后備工作隊(duì)列的先后次序來(lái)挑選作業(yè),先進(jìn)入系統(tǒng)的作業(yè)將優(yōu)先被挑選進(jìn)入主存,創(chuàng)建用戶進(jìn)程,分配所需資源,然后移入就緒隊(duì)列。 時(shí)間片輪轉(zhuǎn)法調(diào)度算法:調(diào)度次序每次把CPU分配給就緒隊(duì)列進(jìn)程/線程使用規(guī) 定的時(shí)間間隔,就緒隊(duì)列中每個(gè)進(jìn)程/線程輪流的運(yùn)行一個(gè)時(shí)間片,當(dāng)時(shí)間片耗盡時(shí),就強(qiáng)迫當(dāng)前運(yùn)行進(jìn)程/線程讓出處理器,轉(zhuǎn)而排列到就緒隊(duì)列尾部,等候下一輪調(diào)度。 優(yōu)先級(jí)調(diào)度:根據(jù)確定的優(yōu)先級(jí)來(lái)選取進(jìn)程/線程,總是選擇就緒隊(duì)列中的優(yōu)先 級(jí)最高者投入運(yùn)行,即優(yōu)先級(jí)越高,先被調(diào)用。 五、數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì) 對(duì)操作系統(tǒng)的各類算法設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)如下: 頁(yè)面替換算法:void FIFO();void LRU();void LFU(); 銀行家算法:void Init()初始化算法 void Bank()銀行家算法 bool Safe()安全性算法 驅(qū)動(dòng)調(diào)度算法: struct MagneticHead//磁頭構(gòu)成{ int site; int count; bool direct; }; struct Range//磁盤磁道范圍 { int mStart; int mEnd; }; struct RequestList//請(qǐng)求序列 { int site; bool state; }; struct Data//基本數(shù)據(jù)集合{ MagneticHead magneticHead; RequestList *requestList; int *executeList; Range range; int length; }; 處理器調(diào)度: typedef struct pcb//時(shí)間片輪轉(zhuǎn)法 { char pname[N]; int runtime; int arrivetime; char state; struct pcb*next; }PCB; typedef struct PCB1//先進(jìn)先出服務(wù) { char ID[3];//進(jìn)程號(hào) char name[10];//進(jìn)程名 char state;//運(yùn)行狀態(tài) floatarrivetime;//到達(dá)時(shí)間 floatstarttime;//進(jìn)程開始時(shí)間 floatfinishtime;//進(jìn)程結(jié)束時(shí)間 floatservicetime;//服務(wù)時(shí)間 float turnaroundtime;//周轉(zhuǎn)時(shí)間 float weightedturnaroundtime;//帶權(quán)周轉(zhuǎn)時(shí)間 struct PCB1 *next;//指向下個(gè)進(jìn)程 }pcb1; struct pcb2 {優(yōu)先級(jí)調(diào)度 char name[10]; char state; int super; int ntime; int rtime; struct pcb2* link; }*ready=NULL,*d; typedef struct pcb2 PCB2; 六、課程設(shè)計(jì)總結(jié) 在本次課程設(shè)計(jì)中,就是講平時(shí)所做的實(shí)驗(yàn)結(jié)合起來(lái),實(shí)現(xiàn)操作系統(tǒng)的各類算法,了解操作系統(tǒng)的運(yùn)行原理以及其基本概念,更好的將操作系統(tǒng)的原理很好的展現(xiàn)出來(lái)。同時(shí),在本次實(shí)驗(yàn)中遇到了很多問(wèn)題,需要我們仔細(xì)的檢查和修改。其次,實(shí)驗(yàn)中為了能更好的體現(xiàn)各類算法的運(yùn)行情況,需要做一個(gè)清晰的界面,以能清楚地看出運(yùn)行結(jié)果。第五篇:操作系統(tǒng)課程設(shè)計(jì)報(bào)告