📄 设计报告.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 + -