?? 設計報告.txt
字號:
實踐目標:
用Win32提供的同步對象解決有限緩沖區問題
實踐內容:
寫一個線程實現C/C++語言程序:一些線程負責找出某個數據范圍的素數,并放到一個數組中,另一些線程負責將數組中的素數按次序取出,并顯示出來。顯示過的數據要從數組中刪除。
要求定義一個全局變量的數組:int prime[9]用于存放找到的待顯示的素數。
三、實踐報告主要內容
設計思路:
找min和max之間素數算法
從min開始到max的每個數num,用2,3,…,sqrt(num)來除它,如果均不能整除則num為素數。
2.進程同步:生產者-消費者算法
do{
……
Produce n item in nexp
……
Wait(empty);
Wait(mutex);
……
Add nexp to buffer
……
Signal(mutex);
Signal(full);
}while(1);
3.產生和顯示素數的過程
讀寫時display和search線程均從prime的第0個元素開始(具體見程序代碼)。Prime數組的元素為0即表明沒有寫入,非0即為已寫入。search線程從下標0開始存放找到的素數,存放前先判斷prime[i]是否為0,為0則存放新找到的素數,否則循環;display線程從下標0開始顯示數組中存放的素數,顯示時先判斷prime[i]是否為0,不為0則顯示該素數,并將prime[i]賦0,否則循環。
整數searchCount和displayCount用于記錄display線程和search線程開啟的個數,以便保證display線程顯示素數和find線程存放素數不會發生死鎖,每次測試時分別將它們初始化為0。主要數據結構:
線程信息結構體:
struct ThreadInfo
{
int serial; //ID
char command; //命令
int num_from; //起始數或顯示數
int num_to; //結束數
};
int searchCount = 0; //search線程數
int displayCount = 0; //display線程數
CRITICAL_SECTION my_section; //臨界區
int prime[9];
主要代碼分析:
詳見代碼注釋。
四、實踐結果
基本數據:
源程序代碼行數 完成實踐投入的總時間 資料查閱時間 編程調試時間 源程序文件
354 4小時 1小時 3小時 ex4.cpp
測試數據設計:
“ex4.dat”文件內容如下:
1.
1 w 10 100
2 w 1 10
3 d 3 0
測試結果分析:
對應于數據2的運行結果圖如下所示:
Reader Priority:
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 2 begins to write the date .
Search thread 2 finish writing the date .
Search thread 2 begins to write the date .
Search thread 2 finish writing the date .
Search thread 2 begins to write the date .
Search thread 2 finish writing the date .
Display thread 3 begins to output prime num .
----------Display thread 3 output the prime num "11".
Display thread 3 finishes outputting prime num .
Display thread 3 begins to output prime num .
----------Display thread 3 output the prime num "13".
Display thread 3 finishes outputting prime num .
Display thread 3 begins to output prime num .
----------Display thread 3 output the prime num "17".
Display thread 3 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
All search and display thread have finished Operating.
The array at last.
29 31 37 19 23 3 5 7 41
Press any key to finish this Program.
Thank you test this Program!
程序運行過程中,線程1、線程2為找素數線程,線程3負責顯示,它們均交叉訪問臨界區,程序運行結果完全正確。
五、實踐體會
同類線程之間的互斥以及不同類線程之間的同步需要通過兩組互斥對象來解決,我在這個問題的處理上采用了semaphore和critical_section這兩種對象來完成這個任務。
實踐中遇到了比較大的困難:
1. 沒有處理死鎖的情況
死鎖情況有兩種,display線程過多導致不夠顯示,search線程過多導致不夠寫入,在這個問題上,我沒采用等待超時的方法,而是用了全局變量來記錄開啟的線程數加上數據上的判斷來避免死鎖。
沒有將handle close導致沒有清空
當程序第二次運行時會出現莫名的錯誤,尋找了好久,才發現沒有把申請的HANDLE close掉。
通過這個程序的實踐,掌握了semaphore的使用以及mutex的使用。
六、參考文獻
1、MSDN
2、《操作系統概念(第六版 影印版)》,Abraham Silberschatz、Peter Baer Galvin、Greg Gagne,
高等教育出版社
附:源程序代碼
#include <windows.h>
#include <conio.h>
#include <fstream.h>
#include <stdio.h>
#include <math.h>
#define INTE_PER_SEC 1000
#define MAX_THREAD_NUM 64
#define MAX_FILE_NUM 32
#define MAX_STR_LEN 32
int searchCount = 0;
int displayCount = 0;
CRITICAL_SECTION my_section;
struct ThreadInfo
{
int serial;
char command;
int num_from;
int num_to;
};
int prime[9];
void GetCommand( char* file );
void thd_display(void* p);
void thd_search(void* p);
BOOL IsPrime(int num);
int GetUsed(int num[9]);
////////////////////////////////////////////////////////
// main function
////////////////////////////////////////////////////////
int main( int agrc, char* argv[] )
{
char ch;
while ( TRUE )
{
// Clear screen
system( "cls" );
// display prompt info
printf("*********************************************\n");
printf(" 1.Test for prime number search and display\n");
printf(" 2.Exit to Windows\n");
printf("*********************************************\n");
printf("Input your choice(1or2): ");
// if the number inputed is error, retry!
do
{
ch = (char)_getch();
}while ( ch != '1' && ch != '2');
system ( "cls" );
if ( ch == '1')
GetCommand("ex4.dat");
else if ( ch == '2')
return 0;
printf("\nPress any key to finish this Program. \nThank you test this Program!\n");
_getch();
} //end while
} //end main
BOOL IsPrime(int num)
{
int i=0;
if (num<2)
{
return FALSE;
}
for (i=2;i<=sqrt(num)+1;i++)
{
if (num % i == 0)
{
return FALSE;
}
}
return TRUE;
}
int GetUsed(int num[9])
{
int i,count=0;
for(i=0;i<9;i++)
{
if(num[i]!=0)
count++;
}
return count;
}
void GetCommand( char* file )
{
DWORD n_thread = 0;
DWORD thread_ID;
DWORD wait_for_all;
int i;
// Tread Object Array
HANDLE h_Thread[MAX_THREAD_NUM];
ThreadInfo thread_info[MAX_THREAD_NUM];
searchCount = 0; //init search thread count
displayCount = 0; //init display thread count
InitializeCriticalSection(&my_section); //init critical section
memset(prime,0,sizeof(prime));
ifstream inFile;
inFile.open(file); //open file
printf( "Reader Priority:\n\n" );
while ( inFile )
{
// read every reader/writer info
inFile>>thread_info[n_thread].serial;
inFile>>thread_info[n_thread].command;
inFile>>thread_info[n_thread].num_from;
inFile>>thread_info[n_thread++].num_to;
inFile.get();
} //end while
for ( i = 0; i < (int)(n_thread); i++)
{
if(thread_info[i].command == 'W' || thread_info[1].command == 'w')
{
searchCount++;
}
else if(thread_info[i].command == 'D' || thread_info[1].command == 'd')
{
displayCount++;
}
}
/* create semaphore */
HANDLE h_semaphore_f = CreateSemaphore(NULL, 0, 9, "Full");
HANDLE h_semaphore_e = CreateSemaphore(NULL, 9, 9, "Empty");
for ( i = 0; i < (int)(n_thread); i++)
{
if(thread_info[i].command == 'W' || thread_info[1].command == 'w')
{
// Create Writer thread
h_Thread[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)(thd_search), &thread_info[i], 0, &thread_ID);
}
else if (thread_info[i].command == 'D' || thread_info[1].command == 'd')
{
// Create Reader thread
h_Thread[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)(thd_display), &thread_info[i], 0, &thread_ID);
}
} //end for
// waiting all thread will been finished
wait_for_all = WaitForMultipleObjects(n_thread,h_Thread,TRUE, -1);
printf("All search and display thread have finished Operating.\n");
//output the array at last
printf("The array at last.\n");
for (i=0;i<9;i++)
{
printf(" %d ",prime[i]);
}
printf("\n");
CloseHandle(h_semaphore_f);
CloseHandle(h_semaphore_e);
}// end GetCommand
void thd_display(void* p)
{
//semaphore
HANDLE h_S_Full = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Full");
HANDLE h_S_Empty = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Empty");
//local var
int m_disnum;
int m_serial;
int i,j;
int now_used;
//get info from para
m_serial = ((ThreadInfo*) (p)) -> serial;
m_disnum = ((ThreadInfo*) (p)) -> num_from;
// begin display
for (i=0;i<m_disnum;i++)
{
now_used=GetUsed(prime);
if(searchCount==0 && now_used == 0)
{
break;
}
//wait semaphore
WaitForSingleObject(h_S_Full, INFINITE);
//enter critical section
EnterCriticalSection( &my_section );
printf("Display thread %d begins to output prime num .\n",m_serial);
for (j=0;j<9;j++)
{
if(prime[j]!=0)
{
printf("----------Display thread %d output the prime num \"%d\".\n",m_serial,prime[j]);
prime[j]=0;
break;
}
}
printf("Display thread %d finishes outputting prime num .\n",m_serial);
//leave critical section
LeaveCriticalSection( &my_section );
//release resource
ReleaseSemaphore(h_S_Empty, 1, NULL);
now_used=GetUsed(prime);
if(searchCount==0 && now_used == 0)
{
break;
}
}
//change the count of display thread
CloseHandle(h_S_Full);
CloseHandle(h_S_Empty);
displayCount--;
}
void thd_search(void* p)
{
//semaphore
HANDLE h_S_Full = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Full");
HANDLE h_S_Empty = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Empty");
//local var
DWORD n_from;
DWORD n_to;
int m_serial;
int i,j;
int primenum[100];
int primecount=0;
int now_used;
//get info from para
m_serial = ((ThreadInfo*) (p)) -> serial;
n_from = ((ThreadInfo*) (p)) -> num_from;
n_to = ((ThreadInfo*) (p)) -> num_to;
//get the primenum to write
for (i=n_from;i<= (int) n_to;i++)
{
if(IsPrime(i)==TRUE)
{
primenum[primecount++]=i;
}
}
//begin the search
for (i=0;i<primecount;i++)
{
now_used=GetUsed(prime);
if(displayCount==0 && now_used==9)
{
break;
}
//wait semaphore
WaitForSingleObject(h_S_Empty, INFINITE);
//enter critical section
EnterCriticalSection( &my_section );
printf("Search thread %d begins to write the date .\n",m_serial);
for(j=0;j<9;j++)
{
if (prime[j]==0)
{
prime[j]=primenum[i];
break;
}
}
printf("Search thread %d finish writing the date .\n",m_serial);
//leave critical section
LeaveCriticalSection( &my_section );
//release resource
ReleaseSemaphore(h_S_Full, 1, NULL);
now_used=GetUsed(prime);
if(displayCount==0 && now_used==9)
{
break;
}
}
//change the count of search thread
CloseHandle(h_S_Full);
CloseHandle(h_S_Empty);
searchCount--;
}
任務五 同步對象實現P、V操作
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -