线程的同步实验

实验二 线程的同步

一、实验目的

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

二、实验准备

等待对象

等待一个对象 等待多个对象
WaitForSingleObject() WaitForMultipleObjects()
在指定时间内等待一个对象 在指定时间内等待多个对象

等待一个对象

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

等待多个对象

DWORD  WaitForMultipleObject(
	DWORD nCount,			//句柄数组中的句柄数
	const HANDLE *lpHandle,	//指向对象句柄数组的指针
	BOOL fwaitALL,			//等待类型
	DWORD dwMilliseconds	//等待时间
);

可等待的对象列表

  • Change notification:变化通知
  • Console input:控制台输入
  • Events:事件
  • Job:作业
  • Mutex:互斥信号量
  • Process:进程
  • Semaphore:计数信号量本次主要用到)
  • Thread:线程 (本次主要用到)
  • Wait-able timer:定时器

如何去等待一个对象

  1. 我们需要立一个Flag,用于在主子线程之间相互告知运行状态。

  2. Flag = 信号量

  3. 创建一个信号量

    hHandle1 = CreateSemaphore(NULL, 0,1, "SemaphoreName1");//创建一个信号量(安全标识符,信号量初始态,信号量最大值,信号量名称)

  4. 打开一个信号量

    hHandle1 = OpenSemaphore( SYNCHRONIZE ISEMAPHORE_ MODIFY_ STATE, NULL,"SemaphoreName1" );

  5. 释放信号量

    rc = ReleaseSemaphore (hHandle1, 1, NULL)(我们需要释放的信号量,进行增几的操作,NULL);

  6. 等待单个对象

    dRes = WaitForSingleObject(hHandle1 , INFINITE); // 主线程无限期地等待子线程结束(句柄,如果没有释放无限运行)

  7. 等待多个对象

    dRes = WaitForMultiple0bjects(3, hHandles, 1, INFINITE); //第三个参数为1或true时,等待数组中所有对象完成,为0或者false时满足一个任务结束就可继续执行

三、实验内容

(一)实验内容

实验一 线程的同步之等待单个对象

子线程 主线程
用于制作麻辣香锅,制作用时5秒 等待子线程执行完毕,打印“开始食用香锅”

实验二 线程的同步之等待多个对象

子线程1 子线程2 子线程3 主线程
用于制作麻辣香锅,制作用时5秒 用于制作什锦菇,制作用时3秒 用于制作米饭,制作用时6秒 等待多个子线程执行完毕,打印”开动了!“

(二)主要代码

实验一主要内容及代码

  • 创建一个信号量并打开,创建一个线程,主线程等待子线程结束,释放信号量。
static HANDLE hHandle1 = NULL;						//静态变量hHandle1用于存放打开的信号量
void chef(){										//用于执行相关的业务逻辑
	printf("麻辣香锅开始制作,预计等待时间5s. \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;
}

实验二主要内容及代码

  • 创建三个线程,当三个线程都执行完毕时,执行主线程
  • 创建三个线程,任意一个线程执行完毕时,执行主线程
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); 	//第三个参数为1,等待所有对象完成
	//dRes=WaitForMultipleObjects(3,hHandles,0,INFINITE);	//第三个参数为0,只需要等待一个对象完成
	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;
}

四、实验结果和总结

实验结果

实验一

  • 创建一个信号量,打开信号量,创建一个子线程制作麻辣香锅,子线程执行完毕,运行主线程,最后释放信号量,结果如图下。
    image
    实验二(1)
  • 创建三个子线程,分别是制作什锦菇3s,制作麻辣香锅5s,制作米饭6s。等三个子线程全部执行完毕,即6s后,主线程运行,餐点上齐。
    image
  • 创建三个子线程,分别是制作什锦菇3s,制作麻辣香锅5s,制作米饭6s。任意一个子线程执行完毕,即3s后,主线程运行,餐点上齐。
    image

实验总结

  • 实验完成了主、子线程的同步,主线程创建子线程后,主线程塞,让子线程先执行,等子线程执行完后,由子线程唤醒主线程。是使我们了解如何使用使用等待对象WaitForSingleObject()或WaitForMultipleObject()及信号量对象CreateSemaphore()、OpenSemaphore()、ReleaseSemaphore()等系统调用,进一步理解线程的同步。

实验中遇到的问题

  • 实验一运行完成后,再次运行,没有显示释放信号量,如下图。
    image

你可能感兴趣的:(线程的同步实验)