操作系统课设之Windows 的互斥与同步
前言
課程設(shè)計開始了,實驗很有意思,寫博客總結(jié)學到的知識
白嫖容易,創(chuàng)作不易,學到東西才是真
本文原創(chuàng),創(chuàng)作不易,轉(zhuǎn)載請注明!!!
本文鏈接
個人博客:https://ronglin.fun/archives/177
PDF鏈接:見博客網(wǎng)站
CSDN: https://blog.csdn.net/RongLin02/article/details/118308666
為了美觀,實驗源代碼在結(jié)尾處,整合版見下
鏈接:https://pan.baidu.com/s/1rXj1QJGuw-BVc5sQWret9w
提取碼:Lin2
操作系統(tǒng)課程設(shè)計源代碼
本次操作系統(tǒng)課程設(shè)計合集
操作系統(tǒng)課設(shè)之Windows 進程管理
操作系統(tǒng)課設(shè)之Linux 進程管理
操作系統(tǒng)課設(shè)之Linux 進程間通信
操作系統(tǒng)課設(shè)之Windows 的互斥與同步
操作系統(tǒng)課設(shè)之內(nèi)存管理
操作系統(tǒng)課設(shè)之虛擬內(nèi)存頁面置換算法的模擬與實現(xiàn)
操作系統(tǒng)課設(shè)之基于信號量機制的并發(fā)程序設(shè)計
操作系統(tǒng)課設(shè)之簡單 shell 命令行解釋器的設(shè)計與實現(xiàn)
僅用于學習,如有侵權(quán),請聯(lián)系我刪除
實驗題目
Windows 的互斥與同步
實驗?zāi)康?/h1>
(1) 回顧操作系統(tǒng)進程、線程的有關(guān)概念,加深對 Windows 線程的理解。
(2) 了解互斥體對象,利用互斥與同步操作編寫生產(chǎn)者-消費者問題的并發(fā)程序,加深對 P (即semWait)、V(即 semSignal)原語以及利用 P、V 原語進行進程間同步與互斥操作的理解。
實驗內(nèi)容實驗原理:
典型例題,生產(chǎn)者消費者問題,利用PV操作和Windows API實現(xiàn)生產(chǎn)者 消費者問題。
實驗步驟:
在Windows下用codeblocks新建一個project,然后將指導書的代碼復(fù)制到項目目錄下的main.cpp文件下。多次運行查看結(jié)果。
修改代碼,調(diào)整生產(chǎn)者線程和消費者線程的個數(shù),使得消費者數(shù)目大與生產(chǎn)者,看看結(jié)果有何不同。
修改代碼,按程序注釋中的說明修改信號量 EmptySemaphore 的初始化方法,看看結(jié)果有何不同。
實驗結(jié)果與分析
源代碼運行結(jié)果
符合預(yù)期,生產(chǎn)者生產(chǎn)一個,消費者消費,如此循環(huán)。
const unsigned short CONSUMERS_COUNT = 5; //消費者的個數(shù)將消費者由1改成5個,結(jié)果如下
和不修改類似。
將信號量如上修改,結(jié)果無輸出
符合預(yù)期,buff空的信號量最開始應(yīng)該是等同于buff大小的,如果按照如上修改,buff空信號量初始化就是0,也就是buff一開始就是滿的,但是實際上buff是空的。所以生產(chǎn)者P(EmptySemaphore)時就是會一直等待,而因為生產(chǎn)者沒生產(chǎn),所以消費者P(FullSemaphore)時也是一直等待,所以就無輸出。
查閱相關(guān)問題和分析代碼,得出以下答案:
1)CreateMutex 中有幾個參數(shù),各代表什么含義。
三個參數(shù),分別是結(jié)構(gòu)體指針;立即擁有互斥體(true);互斥體對象的名字,詳細解釋如下:
lpMutexAttributes SECURITY_ATTRIBUTES,指定一個SECURITY_ATTRIBUTES結(jié)構(gòu),或傳遞零值(將參數(shù)聲明為ByVal As Long,并傳遞零值),表示使用不允許繼承的默認描述符
bInitialOwner BOOL,如創(chuàng)建進程希望立即擁有互斥體,則設(shè)為TRUE。一個互斥體同時只能由一個線程擁有
lpName String,指定互斥體對象的名字。用vbNullString創(chuàng)建一個未命名的互斥體對象。如已經(jīng)存在擁有這個名字的一個事件,則打開現(xiàn)有的已命名互斥體。這個名字可能不與現(xiàn)有的事件、信號機、可等待計時器或文件映射相符。
2)CreateSemaphore 中有幾個參數(shù),各代表什么含義,信號量的初值在第幾個參數(shù)中。
一共有4個參數(shù),分別是結(jié)構(gòu)體指針;信號量對象的初始計數(shù);信號量對象的最大計數(shù);信號量對象的名稱。
結(jié)構(gòu)體指針和信號量對象名稱的參數(shù)的規(guī)則和Mutex的一樣。
3)程序中 P、V 原語所對應(yīng)的實際 Windows API 函數(shù)是什么,寫出這幾條語句。
WaitForSingleObject(EmptySemaphore,INFINITE); //P操作 ReleaseSemaphore(FullSemaphore,1,NULL); //V操作 ReleaseMutex(Mutex); //V操作4)CreateMutex 能用 CreateSemaphore 替代嗎?
嘗試修改程序 4-1,將信號量 Mutex 完全用CreateSemaphore 及相關(guān)函數(shù)實現(xiàn)。寫出要修改的語句。
可以,互斥信號量其實就是二元信號量
只需要修改初始化代碼和V操作代碼即可:
仔細閱讀源程序,找出創(chuàng)建線程的 WINDOWS API 函數(shù),回答下列問題:
線程的第一個執(zhí)行函數(shù)是什么(從哪里開始執(zhí)行)?
它位于創(chuàng)建線程的 API 函數(shù)的第幾個參數(shù)中?
創(chuàng)建線程的函數(shù):CreateThread(),執(zhí)行函數(shù)Producer()/Consumer(),位于第三個參數(shù)
小結(jié)與心得體會
Windows的API看著非常復(fù)雜,參數(shù)很多,而且定義了很多沒用過也沒見過的數(shù)據(jù)類型,由于時間緊迫并沒有深入研究那些復(fù)雜的語法,僅僅是會用信號量和PV操作。不過本次實驗也讓我了解到課本上那些算法和理論離我們并不遙遠,因為我已經(jīng)有過Java多線程程序開發(fā)的經(jīng)歷,Java多線程中同步問題在語法上比C/C++簡單一些,不過兩者用法都非常有各自語言的特點,獲益匪淺。
=w=
源代碼
4-1
#include <windows.h> #include <iostream> const unsigned short SIZE_OF_BUFFER = 2; //緩沖區(qū)長度 unsigned short ProductID = 0; //產(chǎn)品號 unsigned short ConsumeID = 0; //將被消耗的產(chǎn)品號 unsigned short in = 0; //產(chǎn)品進緩沖區(qū)時的緩沖區(qū)下標 unsigned short out = 0; //產(chǎn)品出緩沖區(qū)時的緩沖區(qū)下標 int buffer[SIZE_OF_BUFFER]; //緩沖區(qū)是個循環(huán)隊列 bool p_ccontinue = true; //控制程序結(jié)束 HANDLE Mutex; //用于線程間的互斥 HANDLE FullSemaphore; //當緩沖區(qū)滿時迫使生產(chǎn)者等待 HANDLE EmptySemaphore; //當緩沖區(qū)空時迫使消費者等待17 DWORD WINAPI Producer(LPVOID); //生產(chǎn)者線程 DWORD WINAPI Consumer(LPVOID); //消費者線程int main() { //創(chuàng)建各個互斥信號 //注意,互斥信號量和同步信號量的定義方法不同,互斥信號量調(diào)用的是 CreateMutex 函數(shù),同步信號量調(diào)用的是 CreateSemaphore 函數(shù),函數(shù)的返回值都是句柄。/*結(jié)構(gòu)體指針;立即擁有互斥體(true);互斥體對象的名字*/Mutex = CreateMutex(NULL,FALSE,NULL);/*結(jié)構(gòu)體指針;信號量對象的初始計數(shù);信號量對象的最大計數(shù);信號量對象的名稱*/EmptySemaphore = CreateSemaphore(NULL,SIZE_OF_BUFFER,SIZE_OF_BUFFER,NULL); //將上句做如下修改,看看結(jié)果會怎樣//EmptySemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL);FullSemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER,NULL); //調(diào)整下面的數(shù)值,可以發(fā)現(xiàn),當生產(chǎn)者個數(shù)多于消費者個數(shù)時, //生產(chǎn)速度快,生產(chǎn)者經(jīng)常等待消費者;反之,消費者經(jīng)常等待const unsigned short PRODUCERS_COUNT = 3; //生產(chǎn)者的個數(shù)const unsigned short CONSUMERS_COUNT = 1; //消費者的個數(shù) //總的線程數(shù)const unsigned short THREADS_COUNT = PRODUCERS_COUNT+CONSUMERS_COUNT;HANDLE hThreads[THREADS_COUNT]; //各線程的 handleDWORD producerID[PRODUCERS_COUNT]; //生產(chǎn)者線程的標識符DWORD consumerID[CONSUMERS_COUNT]; //消費者線程的標識符 //創(chuàng)建生產(chǎn)者線程for (int i=0; i<PRODUCERS_COUNT; ++i){hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);if (hThreads[i]==NULL)return -1;} //創(chuàng)建消費者線程for (int i=0; i<CONSUMERS_COUNT; ++i){hThreads[PRODUCERS_COUNT+i]=CreateThread(NULL,0,Consumer,NULL,0,&consumerID[i]);if (hThreads[i]==NULL)return -1;}while(p_ccontinue){if(getchar()) //按回車后終止程序運行{p_ccontinue = false;}}return 0; }//生產(chǎn)一個產(chǎn)品。簡單模擬了一下,僅輸出新產(chǎn)品的 ID 號 void Produce() {std::cout << std::endl<< "Producing " << ++ProductID << " ... ";std::cout << "Succeed" << std::endl; } //把新生產(chǎn)的產(chǎn)品放入緩沖區(qū) void Append() {std::cerr << "Appending a product ... ";buffer[in] = ProductID;in = (in+1)%SIZE_OF_BUFFER;std::cerr << "Succeed" << std::endl; //輸出緩沖區(qū)當前的狀態(tài)for (int i=0; i<SIZE_OF_BUFFER; ++i){std::cout << i <<": " << buffer[i];if (i==in)std::cout << " <-- 生產(chǎn)";if (i==out)std::cout << " <-- 消費";std::cout << std::endl;} } //從緩沖區(qū)中取出一個產(chǎn)品 void Take() {std::cerr << "Taking a product ... ";ConsumeID = buffer[out];buffer[out] = 0;out = (out+1)%SIZE_OF_BUFFER;std::cerr << "Succeed" << std::endl; //輸出緩沖區(qū)當前的狀態(tài)for (int i=0; i<SIZE_OF_BUFFER; ++i){std::cout << i <<": " << buffer[i];if (i==in)std::cout << " <-- 生產(chǎn)";if (i==out)std::cout << " <-- 消費";std::cout << std::endl;} } //消耗一個產(chǎn)品 void Consume() {std::cout << "Consuming " << ConsumeID << " ... ";std::cout << "Succeed" << std::endl; } //生產(chǎn)者 DWORD WINAPI Producer(LPVOID lpPara) {while(p_ccontinue){WaitForSingleObject(EmptySemaphore,INFINITE); //p(empty);WaitForSingleObject(Mutex,INFINITE); //p(mutex);Produce();Append();Sleep(1500);ReleaseMutex(Mutex); //V(mutex);ReleaseSemaphore(FullSemaphore,1,NULL); //V(full);}return 0; } //消費者 DWORD WINAPI Consumer(LPVOID lpPara) {while(p_ccontinue){WaitForSingleObject(FullSemaphore,INFINITE);//P(full);WaitForSingleObject(Mutex,INFINITE); //P(mutex);Take();Consume();Sleep(1500);ReleaseMutex(Mutex); //V(mutex);ReleaseSemaphore(EmptySemaphore,1,NULL); //V(empty);}return 0; }修改版
#include <windows.h> #include <iostream> const unsigned short SIZE_OF_BUFFER = 2; //緩沖區(qū)長度 unsigned short ProductID = 0; //產(chǎn)品號 unsigned short ConsumeID = 0; //將被消耗的產(chǎn)品號 unsigned short in = 0; //產(chǎn)品進緩沖區(qū)時的緩沖區(qū)下標 unsigned short out = 0; //產(chǎn)品出緩沖區(qū)時的緩沖區(qū)下標 int buffer[SIZE_OF_BUFFER]; //緩沖區(qū)是個循環(huán)隊列 bool p_ccontinue = true; //控制程序結(jié)束 HANDLE Mutex; //用于線程間的互斥 HANDLE FullSemaphore; //當緩沖區(qū)滿時迫使生產(chǎn)者等待 HANDLE EmptySemaphore; //當緩沖區(qū)空時迫使消費者等待17 DWORD WINAPI Producer(LPVOID); //生產(chǎn)者線程 DWORD WINAPI Consumer(LPVOID); //消費者線程int main() { //創(chuàng)建各個互斥信號 //注意,互斥信號量和同步信號量的定義方法不同,互斥信號量調(diào)用的是 CreateMutex 函數(shù),同步信號量調(diào)用的是 CreateSemaphore 函數(shù),函數(shù)的返回值都是句柄。/*結(jié)構(gòu)體指針;立即擁有互斥體(true);互斥體對象的名字*/Mutex = CreateSemaphore(NULL,1,1,NULL);/*結(jié)構(gòu)體指針;信號量對象的初始計數(shù);信號量對象的最大計數(shù);信號量對象的名稱*/EmptySemaphore = CreateSemaphore(NULL,SIZE_OF_BUFFER,SIZE_OF_BUFFER,NULL); //將上句做如下修改,看看結(jié)果會怎樣//EmptySemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL);FullSemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER,NULL); //調(diào)整下面的數(shù)值,可以發(fā)現(xiàn),當生產(chǎn)者個數(shù)多于消費者個數(shù)時, //生產(chǎn)速度快,生產(chǎn)者經(jīng)常等待消費者;反之,消費者經(jīng)常等待const unsigned short PRODUCERS_COUNT = 3; //生產(chǎn)者的個數(shù)const unsigned short CONSUMERS_COUNT = 1; //消費者的個數(shù) //總的線程數(shù)const unsigned short THREADS_COUNT = PRODUCERS_COUNT+CONSUMERS_COUNT;HANDLE hThreads[THREADS_COUNT]; //各線程的 handleDWORD producerID[PRODUCERS_COUNT]; //生產(chǎn)者線程的標識符DWORD consumerID[CONSUMERS_COUNT]; //消費者線程的標識符 //創(chuàng)建生產(chǎn)者線程for (int i=0; i<PRODUCERS_COUNT; ++i){hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);if (hThreads[i]==NULL)return -1;} //創(chuàng)建消費者線程for (int i=0; i<CONSUMERS_COUNT; ++i){hThreads[PRODUCERS_COUNT+i]=CreateThread(NULL,0,Consumer,NULL,0,&consumerID[i]);if (hThreads[i]==NULL)return -1;}while(p_ccontinue){if(getchar()) //按回車后終止程序運行{p_ccontinue = false;}}return 0; }//生產(chǎn)一個產(chǎn)品。簡單模擬了一下,僅輸出新產(chǎn)品的 ID 號 void Produce() {std::cout << std::endl<< "Producing " << ++ProductID << " ... ";std::cout << "Succeed" << std::endl; } //把新生產(chǎn)的產(chǎn)品放入緩沖區(qū) void Append() {std::cerr << "Appending a product ... ";buffer[in] = ProductID;in = (in+1)%SIZE_OF_BUFFER;std::cerr << "Succeed" << std::endl; //輸出緩沖區(qū)當前的狀態(tài)for (int i=0; i<SIZE_OF_BUFFER; ++i){std::cout << i <<": " << buffer[i];if (i==in)std::cout << " <-- 生產(chǎn)";if (i==out)std::cout << " <-- 消費";std::cout << std::endl;} } //從緩沖區(qū)中取出一個產(chǎn)品 void Take() {std::cerr << "Taking a product ... ";ConsumeID = buffer[out];buffer[out] = 0;out = (out+1)%SIZE_OF_BUFFER;std::cerr << "Succeed" << std::endl; //輸出緩沖區(qū)當前的狀態(tài)for (int i=0; i<SIZE_OF_BUFFER; ++i){std::cout << i <<": " << buffer[i];if (i==in)std::cout << " <-- 生產(chǎn)";if (i==out)std::cout << " <-- 消費";std::cout << std::endl;} } //消耗一個產(chǎn)品 void Consume() {std::cout << "Consuming " << ConsumeID << " ... ";std::cout << "Succeed" << std::endl; } //生產(chǎn)者 DWORD WINAPI Producer(LPVOID lpPara) {while(p_ccontinue){WaitForSingleObject(EmptySemaphore,INFINITE); //p(empty);WaitForSingleObject(Mutex,INFINITE); //p(mutex);Produce();Append();Sleep(1500);ReleaseSemaphore(Mutex,1,NULL); //V(mutex);ReleaseSemaphore(FullSemaphore,1,NULL); //V(full);}return 0; } //消費者 DWORD WINAPI Consumer(LPVOID lpPara) {while(p_ccontinue){WaitForSingleObject(FullSemaphore,INFINITE);//P(full);WaitForSingleObject(Mutex,INFINITE); //P(mutex);Take();Consume();Sleep(1500);ReleaseSemaphore(Mutex,1,NULL); //V(mutex);ReleaseSemaphore(EmptySemaphore,1,NULL); //V(empty);}return 0; }總結(jié)
以上是生活随笔為你收集整理的操作系统课设之Windows 的互斥与同步的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: flutter listview 滚动到
- 下一篇: vue设置输入框输入长度_vue输入框限