【操作系统】实验三 线程的互斥

实验三

一、实验目的

(1)熟练掌握Windows系统环境下线程的创建与撤销。

(2)熟悉Windows系统提供的线程互斥API。

(3)使⽤Windows系统提供的线程互斥API解决实际问题。

二、实验准备

1.临界区对象:

临界区对象 CriticalSection 包括初始化临界区 InitializeCriticalSection() 、进⼊临界区 EnterCriticalSection () 、退出临界区 LeaveCriticalSection () 及删除临界区 DeleteCriticalSection() 等API函数。


初始化临界区: InitializeCriticalSection() 用于初始化临界区对象

原型:

VOID InitializeCriticalSection ( 
LPCRITICAL_SECTION  lpCriticalSection
 );
//lpCriticalSection:指出临界区对象的地址
进入临界区: EnterCriticalSection() 等待进入临界区的权限,当获得该权限后进入临界区

原型:

VOID EnterCriticalSection ( 
LPCRITICAL_SECTION lpCriticalSection
);
//lpCriticalSection:指出临界区对象的地址
退出临界区: LeaveCriticalSection() 释放临界区的使⽤权限

原型:

VOID LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection 	//指出临界区对象的地址
);
删除临界区 : DeleteCriticalSection() 删除与临界区有关的所有系统资源

原型:

VOID DeleteCriticalSection ( 
LPCRITICAL_SECTION lpCriticalSection 	//指出临界区对象的地址
);
2.互斥对象

互斥对象 Mutex 包括创建互斥对象 CreateMutex() 、打开互斥对象 OpenMutex() 及释放互斥对象 ReleaseMutex() API函数。

创建互斥对象 CreateMutex() 用于创建⼀个互斥对象

原型:

HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, 	//指定安全属性,为NULL时,信号量得到⼀个,默认的安全描述符
BOOL blnitialOwner,		//指定初始的互斥对象。如果该值为TRUE并且互斥对象已经纯在,则调⽤线程获得互斥 对象的所有权,否则调⽤线程不能获得互斥对象的所有权。
LPCTSTR lpName 		//给出互斥对象的名字
);

返回值: 互斥对象创建成功,将返回该互斥对象的句柄。如果给出的互斥对象是系统已经存在的互斥对象,
将返回这个已存在互斥对象的句柄。如果失败,系统返回NULL,可以调⽤函数GetLastError()查询失败的原因

⽤法举例:

static HANDLE  hHandle1=NULL; 
//常⻅⼀个名为"MutexName1"的互斥对象 
hHandle1=CreateMutex(NULL,FALSE, "MutexName1");
打开互斥对象 : OpenMutex()

原型:

HANDLE OpenMutex( 
DWORD dwDesiredAccess,		//指出发开后要对互斥对象进行何种访问
BOOL blnheritHandle, 		//指出返回信号量的句柄是否可以继承
LPCTSTR lpName 				//给出信号量的名字
);

返回值:互斥对象打开成功,将返回该互斥对象的句柄;如果失败,系统返回NULL,可以调⽤函数GetLastError() 查询失败的原因

⽤法举例:

static HANDLE hHandle1 = NULL;  
hHandle=OpenMutex(SYNCHRONIZE,NULL,"MutexName1");//打开⼀个名为"MutexName1"的互斥对象
释放互斥对象:ReleaseMutex()

原型:

BOOL ReleaseMutex(
HANDLE hMUTEX	//Mutex对象的句柄
); 

返回值:如果成功,将返回⼀个⾮0值; 如果失败,系统将返回0,可以调⽤函数 GetLastError()查询失败的原因

三、实验内容

(一)实验内容

能正确的使⽤临界区对象,包括初始化临界区 InitializeCriticalSection()、进⼊临界区 EnterCriticalSection()、退出临界区 LeaveCritical() 及删除临界区 DeleteCriticalSection() 进⼀步理解线程 的互斥。

(二)主要代码

// 003.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "003.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 int count =5; 
static HANDLE h1; 
static HANDLE h2; 
LPCRITICAL_SECTION hCriticalSection;           //定义指向临界区对象的地址指针 
CRITICAL_SECTION Critical;                    //定义临界区
void func1();
void func2();

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	DWORD dwThreadID1,dwThreadID2;
	hCriticalSection=&Critical;
	InitializeCriticalSection(hCriticalSection);

	h1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,
	0,
	(LPTHREAD_START_ROUTINE)func1,
	(LPVOID)NULL,
	0,
	&dwThreadID1);

	if(h1==NULL)
		printf("Thread1 create FAIL!\n");
	else 
		printf("Thread1 create Success!\n");

	h2=CreateThread((LPSECURITY_ATTRIBUTES)NULL,   //创建线程func2 
	0,
	(LPTHREAD_START_ROUTINE)func2,
	(LPVOID)NULL,
	0,
	&dwThreadID2);          

	if(h2==NULL)
		printf("Thread2 create FAIL!\n");
	else
		printf("Thread2 create Success!\n");

	Sleep(1000);
	CloseHandle(h1);
	CloseHandle(h2);
	DeleteCriticalSection(hCriticalSection);       //删除临界区 
	ExitThread(0);

	return nRetCode;
}

void func1(){
	int r1;
	EnterCriticalSection(hCriticalSection);       //进入临界区 
	r1=count;
	_sleep(500);
	r1=r1+1;
	count=r1;
	printf("count in func1=%d\n",count);
	LeaveCriticalSection(hCriticalSection);      //退出临界区
}

void func2(){
	int r2;
	EnterCriticalSection(hCriticalSection);        //进入临界区 
	r2=count;
	_sleep(100);
	r2=r2+1;
	count=r2;
	printf("count in func2=%d\n",count);
	LeaveCriticalSection(hCriticalSection);      //退出临界区
}

四、实验结果与总结

运行结果:

【操作系统】实验三 线程的互斥_第1张图片

总结:

1.复习了直接、间接制约关系、临界资源的使用、访问临界资源的循环进程(Windows操作系统分区与理论分区有一定差别)学习了临界区相关API函数的相关知识,如临界区对象与互斥对象。

2.学习了临界区对象的使用,包括初始化临界区、进入区临界区、退出临界区、删除临界区。

3.通过具体的程序进一步理解了线程的互斥。此前了解最多的是PV操作的理论知识,通过本次实验熟悉了实际的使用。

生产者:

1.申请进入临界区

2.放入产品

3.退出临界区,释放资源

消费者:

1.申请进入临界区

2.取出产品

3.退出临界区,释放资源

此时二者共用临界资源,需要通过互斥信号量来申请临界区的使用权。

  • 遇到的问题与解决方法:

创建线程时变量很多,逗号与分号很容易写错,需要多加注意。

你可能感兴趣的:(操作系统,操作系统,c++)