实验二 线程的同步
一、实验目的
进一步掌握Windows系统环境下线程的创建和撤销;
熟悉Windows系统提供的线程同步API(是Windows提供给应用程序与操作系统的接口)
二、实验准备知识
1.进程的同步:
进程同步机制的主要任务,是对多个相关进程在执行次序上进行协调,使并发执行的诸进程之间能按照一定的规则(或时序)共享系统资源,并能很好地相互合作,从而使程序执行具有可再现性。
2.线程与进程的区别
由于线程具有许多传统进程所具有的特征,所以又称之为轻型进程或进程元,相应地,把传统进程称为重型进程。它相当于只有一个线程的任务。线程是比进程更小的基本单位。
3.线程同步中的“同步”
不是指线程的同步运行,而是指协同步调。协同步调就是按照预定的先后次序进行运行。比如,一人说完另一人再说。
4.相关API函数介绍
1)等待1个对象
WaitForSingleObject() 在指定时间内等待一个对象
DWORD WaitForSingleObject(
HANDLE hHandle,//对象句柄
DWORD dwMilliseconds //等待时间
)
2)等待多个对象
WaitForMultipleObjects() 在指定时间内等待多个对象
DWORD WaitForMultipleObjects(
DWORD nCount, //句柄数组中的句柄数
const HANDLE *lpHAndles, //指向对象句柄数组的指针
BOOL fWaitAll, //等待类型
DWORD dwMilliseconds //等待时间
)
3)可等待的对象列表
①change notification:变化通知
②console input:控制台输入
③Event:事件
④job:作业
⑤mutex:互斥信号量
⑥Process:进程
⑦semaphore:计数信号量
⑧thread:线程
⑨wait-able timer:定时器
三、实验内容
(一)实验情景1
在主线程中创建一个子线程:
子线程:用于制作麻辣香锅,制作用时5秒
主线程:等待子线程执行完毕,打印“开始食用香锅!”
如何等待一个对象:需要设定一个信号量,用于再主子线程之间相互告知运行状态
步骤:
1)创建一个信号量:
hHandle1 = CreateSemaphore(NULL,0,1,"SemaphoreName1");
参数依次表示:安全标志符(为NULL表示默认的安全描述符),信号量的初始态,信号量的最大值,信号量的名称
2)打开一个信号量
hHandle1 = OpenSemaphore(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE,NULL,"SemaphoreName1");
参数依次表示:访问标志(指出打开后要对信号量进行何种访问),继承标志(指出返回的信号量是否可以继承),信号量名
3)释放信号量
rc = ReleaseSemaphore(hHandle1,1,NULL);
参数依次表示:信号量对象句柄(创建或打开信号量时给出的信号量对象句柄),信号量要增加数值(信号量要增加数值),信号量要增加的数值地址(32位的一个变量)
4)等待单个对象
dRes = WaitForSingleObject(hHandle1,INFINITE);
参数依次表示:信号量的句柄,INFINITE指的是如果信号量如果信号量没有释放将无限期的释放下去
5)等待多个对象
dRes = WaitForMultipleObjects(3,hHandles,1,INFINITE);
参数依次表示:等待对象的个数,等待多个对象数组的指针,第三个参数为1或true时就要等待数组当中所有的对象,INFINITE指的是如果信号量如果信号量没有释放将无限期的释放下去
// 01.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "01.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// The one and only application object
CWinApp theApp;
using namespace std;
static HANDLE hHandle1=NULL;
void chef(){
printf("麻辣香锅开始制作,预计等待时间5秒。\n");
Sleep(5000);
printf("麻辣香锅制作完成!");
BOOL rc;
DWORD err;
rc = ReleaseSemaphore(hHandle1,1,NULL);
err=GetLastError();
printf("ReleaseSemaphore err=%d\n",err);
if(rc==0){
printf("Semaphore Release Fail!rc=%d\n",rc);
}
else{
printf("Semaphore Release Success!rc=%d\n",rc);
}
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
DWORD dRes,err;
hHandle1 = CreateSemaphore(NULL,0,1,"SemaphoreName1");
if (hHandle1==NULL)printf("Semaphore Create Fail!\n");
else printf("Semaphore Create Success!\n");
hHandle1=OpenSemaphore(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE,NULL,"SemaphoreName1"); //打开信号量
if (hHandle1==NULL) printf("Semaphore Open Fail!\n");
else printf("Semaphore Open Success!\n");
HANDLE handle1=NULL;
DWORD ThreadID1=NULL;
handle1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE) chef,(LPVOID)NULL,0,&ThreadID1); //创建子线程
dRes=WaitForSingleObject(hHandle1,INFINITE); //主线程等待子线程结束
err=GetLastError();
if(err==0){
printf("麻辣香锅上菜完毕,请开动吧。\n");
}
else{
printf("WaitForSingleObject err=%d\n",err);
if(dRes==WAIT_OBJECT_0) printf("TIMEOUT!dRes=%d\n",dRes);
else if(dRes==WAIT_OBJECT_0) printf("WAIT_OBJECT!dRes=%d\n",dRes);
else if(dRes==WAIT_ABANDONED) printf("WAIT_ABANDONED!dRes=%d\n",dRes);
else printf("dRes=%d\n",dRes);
}
return 0;
}
2)实验情景2
void chef(int meal_code){
if(meal_code==0)
{
Sleep(5000);
printf("麻辣香锅制作完成!\n");
}
else if(meal_code==1)
{
Sleep(3000);
printf("什锦菇制作完成!\n");
}
else if(meal_code==2)
{
Sleep(6000);
printf("米饭制作完成!\n");
}
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
DWORD dRes,err;
HANDLE handle1=NULL;
HANDLE handle2=NULL;
HANDLE handle3=NULL;
DWORD ThreadID1=NULL;
DWORD ThreadID2=NULL;
DWORD ThreadID3=NULL;
int a=0;
int b=1;
int c=2;
handle1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE) chef,(LPVOID)a,0,&ThreadID1);
handle2=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE) chef,(LPVOID)b,0,&ThreadID2);
handle3=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE) chef,(LPVOID)c,0,&ThreadID3);
HANDLE hHandles[3];
hHandles[0]=handle1;
hHandles[1]=handle2;
hHandles[2]=handle3;
dRes = WaitForMultipleObjects(3,hHandles,1,INFINITE);
err=GetLastError();
if(err==0){
printf("所有的餐点已经上齐,请开动吧。\n");
}
else{
printf("WaitForMultipleObjects err = %d\n",err);
if(dRes==WAIT_TIMEOUT) printf("TIMEOUT!dRes=%d\n",dRes);
else if(dRes==WAIT_OBJECT_0) printf("WAIT_OBJECT!dRes=%d\n",dRes);
else if(dRes==WAIT_ABANDONED) printf("WAIT_ABANDONED!dRes=%d\n",dRes);
else printf("dRes=%d\n",dRes);
}
return 0;
}
四、实验结果与总结
在主线程中创建一个子线程:
子线程:用于制作麻辣香锅,制作用时5秒
主线程:等待子线程执行完毕,打印“开始食用香锅!”
如何等待一个对象:需要设定一个信号量,用于再主子线程之间相互告知运行状态
线程同步中的“同步”
不是指线程的同步运行,而是指协同步调。协同步调就是按照预定的先后次序进行运行。比如,一人说完另一人再说。