中北大学课程设计说明书学院、系:软件学院专业:软件工程班级:13140A05学生姓名:学号:设计题目:基于Windows的线程控制与同步起迄日期: 2015年12月28日~2016年1月8日指导教师:日期: 2015年12月25日一、设计目的进程同步是处理机管理中一个重要的概念。
本设计要求学生理解和掌握Windows中线程控制与同步机制的相关API函数的功能,能够利用这些函数进行编程。
二、任务概述(1)实现生产者-消费者问题。
(2)实现读/写者问题。
(3)实现哲学家就餐问题。
三、总体设计(1)生产者-消费者问题。
是一个多线程同步问题的经典案例。
该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。
生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。
与此同时,消费者也在缓冲区消耗这些数据。
该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
(2)读/写者问题。
创建一个控制台程序,此程序包含n个线程。
用这n个线程来表示n个读者或写者。
每个线程按相应测试数据文件(后面有介绍)的要求进行读写操作。
用信号量机制分别实现读者优先或写者优先的读者-写者问题。
(3)实现哲学家就餐问题。
用来演示在并行计算中多线程同步(Synchronization)时产生的问题。
在1971年,著名的计算机科学家艾兹格·迪科斯彻提出了一个同步问题,即假设有五台计算机都试图访问五份共享的磁带驱动器。
稍后,这个问题被托尼·霍尔重新表述为哲学家就餐问题。
这个问题可以用来解释死锁和资源耗尽。
有服务生解法,资源分级解法,Chandy/Misra解法。
四、详细设计函数(1)生产者-消费者问题#include <windows.h>#include <conio.h>#include <stdio.h>#include <time.h>#define MAX 20 //定义缓冲池的最大容量是20int count;void Proclucer(){int k,a=0;while(1){if(count >= MAX){printf("缓冲池已满!等待2 秒!\n");Sleep(1000);}else{k=rand();if(k%2==0){a++;count++;printf("生产了一个产品!当前产品的数量是: %d 生产产品总数:%d \n\n",count,a);}Sleep(600);}}}void Consumer(){int k,b=0;while(1){if(count <= 0){printf("缓冲池已空!等待2 秒!\n");Sleep(1000);}else{k=rand();if(k%2!=0){b++;count--;printf("取出了一个产品!当前产品的数量是: %d 取出产品总数:%d\n",count,b);}Sleep(600);}}}int tStop() //创建一个停止函数{getch();return 11;}void Start(){int m;HANDLEahThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Proclucer,NULL,0,NULL); HANDLEbhThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Consumer,NULL,0,NULL); HANDLE hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)tStop,NULL,0,NULL); m=tStop();if(m==11){CloseHandle(ahThread);CloseHandle(bhThread);CloseHandle(hThread);printf("\nClose Thread Success!\nh");}}int main(){Start();printf("\n");}(2)读/写者问题#include <stdio.h>#include <process.h>#include <windows.h>//设置控制台输出颜色BOOL SetConsoleColor(WORD wAttributes){HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);if (hConsole == INV ALID_HANDLE_V ALUE)return FALSE;return SetConsoleTextAttribute(hConsole, wAttributes);}const int READER_NUM = 5; //读者个数//关键段和事件CRITICAL_SECTION g_cs, g_cs_writer_count;HANDLE g_hEventWriter, g_hEventNoReader;int g_nReaderCount;//读者线程输出函数(变参函数的实现)void ReaderPrintf(char *pszFormat, ...){va_list pArgList;va_start(pArgList, pszFormat);EnterCriticalSection(&g_cs);vfprintf(stdout, pszFormat, pArgList);LeaveCriticalSection(&g_cs);va_end(pArgList);}//读者线程函数unsigned int __stdcall ReaderThreadFun(PVOID pM){ReaderPrintf(" 编号为%d的读者进入等待中...\n", GetCurrentThreadId());//等待写者完成WaitForSingleObject(g_hEventWriter, INFINITE);//读者个数增加EnterCriticalSection(&g_cs_writer_count);g_nReaderCount++;if (g_nReaderCount == 1)ResetEvent(g_hEventNoReader);LeaveCriticalSection(&g_cs_writer_count);//读取文件ReaderPrintf(" 编号为%d的读者开始读取文件...\n", GetCurrentThreadId());Sleep(rand() % 100);//结束阅读,读者个数减小,空位增加ReaderPrintf(" 编号为%d的读者结束读取文件\n", GetCurrentThreadId());//读者个数减少EnterCriticalSection(&g_cs_writer_count);g_nReaderCount--;if (g_nReaderCount == 0)SetEvent(g_hEventNoReader);LeaveCriticalSection(&g_cs_writer_count);return 0;}//写者线程输出函数void WriterPrintf(char *pszStr){EnterCriticalSection(&g_cs);SetConsoleColor(FOREGROUND_RED);printf(" %s\n", pszStr);SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);LeaveCriticalSection(&g_cs);}//写者线程函数unsigned int __stdcall WriterThreadFun(PVOID pM){WriterPrintf(" ┍------------------┑\n 写者线程进入等待中\n ┕------------------┙");//等待读文件的读者为零WaitForSingleObject(g_hEventNoReader, INFINITE);//标记写者正在写文件ResetEvent(g_hEventWriter);//写文件WriterPrintf(" ┍------------------┑\n 写者开始写文件\n ┕------------------┙");Sleep(rand() % 100);WriterPrintf(" ┍------------------┑\n 写者结束写文件\n ┕------------------┙");//标记写者结束写文件SetEvent(g_hEventWriter);return 0;}int main(){printf("-------------------读者写者问题------------------>>13140A05班12组<<-------------\n");//初始化事件和信号量InitializeCriticalSection(&g_cs);InitializeCriticalSection(&g_cs_writer_count);//手动置位,初始已触发g_hEventWriter = CreateEvent(NULL, TRUE, TRUE, NULL);g_hEventNoReader = CreateEvent(NULL, FALSE, TRUE, NULL);g_nReaderCount = 0;int i;HANDLE hThread[READER_NUM + 1];//先启动二个读者线程for (i = 1; i <= 2; i++)hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);//启动写者线程hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);Sleep(50);//最后启动其它读者结程for ( ; i <= READER_NUM; i++)hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);WaitForMultipleObjects(READER_NUM + 1, hThread, TRUE, INFINITE);for (i = 0; i < READER_NUM + 1; i++)CloseHandle(hThread[i]);//销毁事件和信号量CloseHandle(g_hEventWriter);CloseHandle(g_hEventNoReader);DeleteCriticalSection(&g_cs);DeleteCriticalSection(&g_cs_writer_count);//return 0;system("pause");}(3)实现哲学家就餐问题#define WIN32_LEAN_AND_MEAN#include <cstdio>#include <cstdlib>#include <Windows.h>DWORD WINAPI PhilosoperThreadFunc(LPVOID);#define PHILOSOPERS 5//定义5个哲学家HANDLE chop_sticks[PHILOSOPERS];HANDLE threads[PHILOSOPERS];int main(int argc, char** argv){for (int i = 0; i<DESKTOPHORZRES; ++i)chop_sticks[i] = CreateMutex(NULL, //缺省安全性FALSE, //初始时拥有,此时互斥体为无信号状态NULL //匿名的);//创建互斥体for (int i = 0; i<PHILOSOPERS; ++i)threads[i] = CreateThread(NULL,0,PhilosoperThreadFunc,(PVOID)i,0,NULL);//创建线程WaitForMultipleObjects(PHILOSOPERS, threads, TRUE, INFINITE);//等待FHILOSOPERS终止return EXIT_SUCCESS;}DWORD WINAPI PhilosoperThreadFunc(LPVOID n){int i = (int)n;HANDLE my_chop_sticks[2];my_chop_sticks[0] = chop_sticks[i];my_chop_sticks[1] = chop_sticks[(i - 1>0) ? i - 1 : PHILOSOPERS];srand(GetTickCount());//调用随机数while (1){Sleep((rand() % 8) * 500 + 500);//随机等待几秒钟printf("哲学家%d 想吃饭\n", i);WaitForMultipleObjects(2, my_chop_sticks, TRUE, 0);//等待两个线程的终止printf("哲学家%d 正在吃\n", i);ReleaseMutex(my_chop_sticks[0]);//释放my_chop_sticks[0] 使可以接受信号ReleaseMutex(my_chop_sticks[1]);//释放my_chop_sticks[1] 使可以接受信号printf("哲学家%d 吃完了\n", i);}}五、程序运行数据及其结果(1)实现生产者-消费者问题。