操作系统实验二——线程的同步

**

操作系统实验二——线程的同步

**

一、 实验目的

(1)进一步掌握windows系统环境下线程的创建和撤销。
(2)熟悉windows系统提供的线程同步API(是WINDOWS提供给应用程序与操作系统的接口)。
(3)使用windows系统提供的线程同步API解决实际问题。

二、 实验准备

1)WaitForMultipleObject() //用于等待一个对象。
他等待的对象可以为以下对象之一:
1、Change notification:变化通知。
2、Console input:控制台输入。
3、Events:事件。
4、Job:作业。
5、Mutex:互斥信号量。
6、Process:进程。
7、Semaphore:计数信号量。
8、Thread:线程。
9、Waitable timer:定时器。
原型:

DWORD WaitForSingleObject(
           HANDLE hHandle,             //对象句柄DWORD 
           dwMilliseconds                     //等待时间
           );

参数说明:
hHandle:等待对象的对象句柄。该对象句柄必须为SYNCHRONIZE([ˈsɪŋkrənaɪz],同步)访问。
dwMilliseconds:等待时间,单位为ms。若改值为0,函数在测试对象的状态后立即返回,若为INFINITE(无限的),函数一直等待下去,直到收到一个信号将其唤醒。
返回值:如果返回成功,其返回值说明是何种事件导致函数返回。
用法举例:

Staitic   HANDLE   hHandle1=NULL;
			DWORD   dRes;
			dRes=WaitForSingleObject(hHandle1, 10);  //等待对象的句柄为hHandle,等待时间为1000ms。

2)WaitForMultipleObject() //等待多个对象
在指定时间内等待多个对象,他等待的对象与WaitForSingleObject()相同。
原型:

DWORD  WaitForMultipleObject(
DWORD  nCount,             //句柄数组中的句柄数XONST
HANDLE *lpHandles,     //指向对象句柄数组的指针BOOL 
fWaitAll,              //等待类型DWORD  
dwMilliseconds        //等待时间
};

参数说明:
nCount:由 指 针*lpHandles指 定 的 句 柄 数 组 中 的 句 柄 数 , 最 大 数 是MAXIMUM_WAIT_OBJECTS。
*lpHandles:指向对象句柄数组的指针。
fWAitAll:等待类型。若存为true,当由lpHandles数组指定的所有对象被唤醒时函数返回;若为FALSE,当由lpHandles数组制定的某一个对象被唤醒时函数返回,且有返回值说明事由哪个对象引起的函数返回。
dwMilliseconds :等待时间。单位为ms。若该值为0,函数测试对象的状态后立即返回;若为INFINITE,函数一直等待下去,直到收到一个信号将其唤醒。
返回值:如果成功返回,其返回值说明是何种事件导致函数返回。
3)信号量对象(semaphore)包括创建信号量(CreateSemaphore())打开信号量OpenSemaphore()及增加信号量的值(ReleaseSemaphore())API函数。
CreateSemaphore() //用于创建一个信号量。
原型:

HANDLE  CreateSemaphore(
LPSECURITY_ATTRIBUTES  lpSemaphoreAttributes,//安全属性LONG 
lInitialCount,                        //信号量对象初始值LONG  
liMaximumCount,                    //信号量最大值LPCTSTR  
lpName//信号量名;

参数说明:
lpSemaphoreAttributes:指定安全属性,为null是,信号量得到一个默认的安全描述符。
lInitialCount:指定信号量对象的初始值。该值必须大于等于0,小于等于lMaximumCount 。当其值大于0是,信号量被唤醒。当该函数释放了一个等待该信号量的线程时,lInitialCount值减1,当调用函数ReleaseSemaphore()时,按其指定的数量加一个值。
lMaximumCount:指出该信号量的最大值,该值必须大于0.
lpName:给出该信号量的名字。
返回值:信号量创建成功,将返回该型号量的句柄。如果给出的信号量名是系统已经存在的信号量,将返回这个已经存在的信号量的句柄。如果失败,系统返回null,还可以调用函数GEtLastError()查询失败的原因。
用法举例:

Static HANDLE hHandle1=null;//创建一个信号量,其初值为0,最大值为5,信号量的名字为“SemphoreName1”hHnadle1= CreateSemaphore(NULL,0,5,"SemphoreName1");

OpenSemaphore() //用于打开一个信号量。
原型:

HANDLEOpenSemaphore(
DWORDdwDesidedAccess,               //访问标志BOOL  
bInheritHandle,                   //继承标志  LPCTSTR
lpNme                          //信号量名
);

参数说明:
(1)dwDesiredAccess:指出打开后要对信号量进行何种访问。
(2)bInheritHandle:指出返回的的信号量句柄是否可以继承。
(3)lpName:给出信号量的名字
返回值:信号量打开成功,将返回信号量的句柄;如果失败,系统返回null,可以调用函数GetLastError()查询失败的原因。
用法举例:

Static HANDLE hHandle1=null;//打开一个名为 ” SemphoreName1 ” 的信号量,之后可使用ReleaseSemaphore()函数增加信号量的值hHandle1=OpenSemaphore(SEMAPHORE_MOFDIFY_START,NULL,   ”SemphoreName1” );

ReleaseSemaphore() //用于增加信号量的值。
原型:

BOOL ReleaseSemaphore(
HANDLE  hSemaphore,          //信号量对象句柄LONG 
lReleaseCount,            //信号量要增加数值LPLONG 
lpPreiousCount           //信号量要增加数值地址
);

参数说明:
(1).hSemaphore:创建或打开信号量时给出的信号量对象句柄。Windows NT中建议使用SEMAPHORE_MODIFY_STARTE访问属性打开该信号量。
(2). lReleaseCount:信号量要增加数值。该值必须大于0。如果增加该值后大于信号创建时给出的lMaximumCount值,则增加操作失效,函数返回FALSE。
(3). lpPreiousCount :接收信号量的一个32位的一个变量。若不需要接受该值,可以指定为null。返回值: 如果成功,将返回一个非0值;如果失败,系统返回一个0,可以调用一个GetLastError()查询失败的原因。
用法举例:

Static HANDLE hHandle1=NULL;
BOOL rc;
rc= ReleaseSemaphore(hHandle1,1NULL);//给信号量的值加1;

三、 实验内容

完成主子两个线程之间的同步,要求子线程先执 行。在主线程中使用系统调用CreateThread()创建一个子线程。主线程创建一个子线程后进入阻塞状态,直到子线程运行完毕后唤醒主线程。
实验代码:
(1)等待一个对象:

using namespace std;
static HANDLE hHandle1=NULL;

void chef(){
	printf("馒头开始制作,预计等待时间5秒。\n");
	Sleep(5000);
	printf("馒头制作完成!\n");

	BOOL rc;
	DWORD err;

	rc=ReleaseSemaphore(hHandle1,1,NULL);
	err=GetLastError();                    //子线程唤醒主线程
	printf("ReleaseSemaphore err=%d\n",err);
	if(rc==0){
		printf("Semaphore Release Fail!\n");
	}
	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_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 nRetCode;
}

(2)等待多个对象

using namespace std;

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(9000);
	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 nRetCode;
}

四、实验结果与总结

实验完成了主、子线程的同步,主线程创建子线程后,主线程塞,让子线程先执行,等子线程执行完后由子线程唤醒子线程。主、子线程运行情况如图:
在这里插入图片描述
米饭的等待时间为3秒,馒头的等待时间为5秒,馄饨的等待时间为9秒,所以米饭先打印完毕,馄饨最后打印完毕。
在这里插入图片描述
将WaitForMultipleObjects的返回类型改为0时,某一个对象被唤醒时函数即返回,且有返回值说明事由哪个对象引起的函数返回。 在这里插入图片描述

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值