实验2:线程同步一、实验目的(1)掌握Windows2000环境下,线程同步。
(2)熟悉Windows2000提供的线程同步与互斥API。
(3)用Windows2000提供的线程同步与互斥API解决实际问题(producer-consumer)。
二、实验内容生产者与消费者问题的实现。
在Windows 2000环境下,创建一组“生产者”线程和一组“消费者”线程,并建立一个长度为N的全局数组作为共享缓冲区。
“生产者”向缓冲区输入数据,“消费者”从缓冲区读出数据。
当缓冲区满时,“生产者”必须阻塞,等待“消费者”取走缓冲区数据后将其唤醒。
当缓冲区空时,“消费者”阻塞,等待“生产者”生产了产品后将其唤醒。
试用信号量实现“生产者”与“消费者”线程之间的同步。
三、实验环境(1)使用的操作系统及版本。
Windows xp professional(2)使用的编译系统及版本。
Visual c++ 6.0四、实验步骤1.等待一个对象(相当于p操作)WaitForSingleObject用于等待一个对象。
它等待的对象可以为:Change notification:变化通知。
Console input:控制台输入。
Event:事件。
Job:作业。
Mutex:互斥信号量。
Process:进程。
Semaphore:计数信号量。
Thread:线程。
Waitable timer:定时器。
返回值:如果成功返回,其返回值说明是何种事件导致函数返回。
访问描述WAIT_ABANDONED 等待的对象是一个互斥(mutex)对象,该互斥对象没有被拥有它的线程释放,它被设置为不能被唤醒。
WAIT_OBJECT_0 指定对象被唤醒。
WAIT_TIMEOUT 超时。
2.创建信号量CreateSemaphore用于创建一个信号量。
返回值:信号量创建成功,将返回该信号量的句柄。
如果给出的信号量名是系统已经存在的信号量,将返回这个已存在信号量的句柄。
如果失败,系统返回NULL,可以调用函数GetLastError查询失败的原因。
3.打开信号量OpenSemaphore用于打开一个信号量。
返回值:信号量打开成功,将返回该信号量的句柄。
如果失败,系统返回NULL,可以调用函数GetLastError查询失败的原因。
4.增加信号量的值ReleaseSemaphore用于增加信号量的值。
返回值:如果成功,将返回一个非0值。
如果失败,系统返回0,可以调用函数GetLastError 查询失败的原因。
方法一:程序代码:#include<windows.h>#include<iostream.h>static HANDLE S1,S2;static HANDLE hMutex;void producer(int n){for(int i=1;i<=3;i++){WaitForSingleObject(S1,INFINITE);WaitForSingleObject(hMutex,INFINITE);cout<<"生产者"<<n<<" 第"<<i<<"次生产产品"<<endl;ReleaseMutex(hMutex);ReleaseSemaphore(S2,1,NULL);}}void consumer(int n){for(int i=1;i<=3;i++){WaitForSingleObject(S2,INFINITE);WaitForSingleObject(hMutex,INFINITE);cout<<"消费者"<<n<<" 第"<<i<<"次消费产品"<<endl;ReleaseMutex(hMutex);ReleaseSemaphore(S1,1,NULL);}}void main(void){static HANDLE hHandle1,hHandle2,hHandle3,hHandle4;DWORD dwID1,dwID2,dwID3,dwID4;S1=CreateSemaphore(NULL,1,1,"Semphore1");S2=CreateSemaphore(NULL,0,1,"Semphore2");hMutex=CreateMutex(NULL,FALSE,NULL);hHandle1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_STA RT_ROUTINE)producer,(LPVOID)1,0,&dwID1);hHandle3=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_STA RT_ROUTINE)consumer,(LPVOID)1,0,&dwID3);hHandle2=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_STA RT_ROUTINE)producer,(LPVOID)2,0,&dwID2);hHandle4=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_STA RT_ROUTINE)consumer,(LPVOID)2,0,&dwID4);Sleep(1000);}5.初始化临界区InitializeCriticalSection用于初始化临界区对象。
返回值:以下两个api相当于pv源语操作6.进入临界区EnterCriticalSection等待进入临界区的权限,当获得该权限后进入临界区。
返回值:该函数没有返回值。
7.退出临界区LeaveCriticalSection释放临界区的使用权限。
返回值:该函数没有返回值。
方法二:程序源代码:#include<windows.h>#include<iostream.h>static HANDLE S1,S2;//定义两个信号量 S1空间CRITICAL_SECTION CS; //定义一个临界区void producer(int n){for(int i=1;i<=3;i++){WaitForSingleObject(S1,INFINITE);EnterCriticalSection(&CS);cout<<"生产者"<<n<<" 第"<<i<<"次生产产品"<<endl;LeaveCriticalSection(&CS);ReleaseSemaphore(S2,1,NULL);}}void consumer(int n){for(int i=1;i<=3;i++){WaitForSingleObject(S2,INFINITE);EnterCriticalSection(&CS);cout<<"消费者"<<n<<" 第"<<i<<"次消费产品"<<endl;LeaveCriticalSection(&CS);ReleaseSemaphore(S1,1,NULL);}}void main(void){static HANDLE hHandle1,hHandle2,hHandle3,hHandle4;DWORD dwID1,dwID2,dwID3,dwID4;S1=CreateSemaphore(NULL,1,1,"Semphore1");S2=CreateSemaphore(NULL,0,1,"Semphore2");InitializeCriticalSection(&CS);hHandle1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_STA RT_ROUTINE)producer,(LPVOID)1,0,&dwID1);hHandle2=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_STA RT_ROUTINE)producer,(LPVOID)2,0,&dwID2);hHandle3=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_STA RT_ROUTINE)consumer,(LPVOID)1,0,&dwID3);hHandle4=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_STAR T_ROUTINE)consumer,(LPVOID)2,0,&dwID4);Sleep(1000);}程序流程图:Main函数:挂起线程唤起线程Consumer 函数:不成立不成立 挂起线程 唤起线程《Windows。