操作系统实验:用临界区对象和互斥信号量实现线程的互斥

实验三:线程的互斥


一、实验目的

(1)熟练掌握Windows系统环境下线程的创建与撤销。
(2)熟悉Windows系统提供的线程互斥API。 
(3)使⽤Windows系统提供的线程互斥API解决实际问题。
(4)分别两种方法--使用临界区对象和互斥对象完成实验:线程的互斥。

二、实验准备

LPCRITICAL_SECTION hCriticalSection; ----定义指向临界区对象的地址指针
CRITICAL_SECTION Critical; ----定义临界区

(1).临界区对象
  临界区对象(CriticalSection)包括初始化临界区(InitializeCriticalSection())、进入临界区(EnterCriticalSection())、退出临界区(LeaveCriticalSection())及删除临界区(DeleteCriticalSection())等API函数。
  1.初始化临界区
InitializeCriticalSection()⽤于初始化临界区对象。
   原型:
VOID InitializeCriticalSection(
LPCRITICAL_SECTION  lpCriticalSection );
   参数说明:
lpCriticalSection:指出临界区对象的地址。
  2.进⼊临界区
EnterCriticalSection()等待进入临界区的权限,当获得该权限后进入临界区。
   原型:
VOID EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection );
   参数说明:
lpCriticalSection:指出临界区对象的地址。
  3.退出临界区
LeaveCriticalSection()释放临界区的使⽤权限。
   原型:
VOID LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection );
   参数说明:
lpCriticalSection:指出临界区对象的地址。
  4.删除临界区
DeleteCriticalSection()删除与临界区有关的所有系统资源。
   原型:
VOID DeleteCriticalSection(
LPCRITICAL_SECTION  lpCriticalSection );
   参数说明:
lpCriticalSection:指出临界区对象的地址

static HANDLE hMutex = NULL;-----定义一个句柄

(2).互斥对象 Mutex
  互斥对象(Mutex)包括创建互斥对象(CreateMutex())、打开互斥对象(OpenMutex())及释
放互斥对象(ReleaseMutex())API函数。
  1.创建互斥对象
CreateMutex()⽤于创建⼀个互斥对象。
   原型:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexASributes,
BOOL bInitialOwner,
LPCTSTR lpName );
   参数说明:
lpMutexASributes:指定安全属性,为NULL时,信号量得到⼀个,默认的安全描述符。
bIni2alOwner:指定初始的互斥对象。如果该值为TRUE并且互斥对象已经存在,则调⽤线程获得互斥
对象的所有权,否则调⽤线程不能获得互斥对象的所有权。想要知道互斥对象是否已经存在,参⻅返回
值说明。
lpName:给出互斥对象的名字。
  2.打开互斥对象
OpenMutex()⽤于打开⼀个互斥对象。
   原型:
HANDLE OpenMutex(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName );
   参数说明:
指明系统安全属性⽀持的对互斥对象所有可能的访问。如果系统安全属性不⽀持,则不能获得对互
斥对象访问权。
dwDesireAccess:指出发开后要对互斥对象进⾏何种访问。
bInheritHandle: 指出返回信号量的句柄是否可以继承。
IpName : 给出信号量的名字。
  3.释放互斥对象
ReleaseMutex() ⽤于释放互斥对象。
   原型:
BOOL ReleaseMutex(
HANDLE hMutex;); 
   参数说明:
hMutex:Mutex对象的句柄。CreateMutex()和OpenMutex()函数返回该句柄。

三、实验内容

(一)实验内容
实验一:
  用临界区对象来完成两个⼦线程之间的互斥。在主线程中使⽤系统调⽤ CreateThread()创建两个⼦线程,
  并使两个⼦线程互斥的使⽤全局变量 count(计数器)。

实验二:
  用互斥对象(Mutex)来完成两个⼦线程之间的互斥。在主线程中使⽤系统调⽤ CreateThread()创建两个⼦线程,
  并使两个⼦线程互斥的使⽤全局变量 count(计数器)。
  
(二)主要代码
实验一代码:
#include "stdafx.h"
#include "03.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 wuyilin;
CRITICAL_SECTION WYL;
void Funcion1();
void Funcion2();

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

	DWORD dwThreadID1, dwThreadID2;

	//将指向临界区对象的指针指向临界区
	wuyilin=&WYL;
	//初始化临界区
    InitializeCriticalSection(wuyilin);

	h1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,
	0,
	(LPTHREAD_START_ROUTINE)Funcion1,
	(LPVOID)NULL,
	0,&dwThreadID1);            //创建线程  Funcion1
	if (h1==NULL) printf("Thread1 create FAIL!\n");
	else printf("Thread1 create Success!\n");

	h2=CreateThread((LPSECURITY_ATTRIBUTES)NULL,
	0,
	(LPTHREAD_START_ROUTINE)Funcion2,
	(LPVOID)NULL,  
	0,&dwThreadID2);           //创建线程  Funcion2
	if (h2==NULL) printf("Thread2 create FAIL!\n");
	else printf("Thread2 create Success!\n");

	Sleep(1000);
	CloseHandle(h1);
	CloseHandle(h2);
	DeleteCriticalSection(wuyilin);       //删除临界区
	ExitThread(0);
	return nRetCode;
}

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

void Funcion2()
{ 
	int r2;
	EnterCriticalSection (wuyilin);        //进入临界区
	r2=count;
	Sleep(100);
	r2=r2+1;
	count=r2;
	printf("count in Funcion2=%d\n",count);
	LeaveCriticalSection (wuyilin);        //退出临界区
}
实验二代码:
#include "stdafx.h"
#include "032.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;
static HANDLE hMutex = NULL;   //定义一个句柄
void Funcion1();
void Funcion2();

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

	DWORD dwThreadID1, dwThreadID2;

	hMutex = CreateMutex(NULL, FALSE, NULL);

	h1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,
	0,
	(LPTHREAD_START_ROUTINE)Funcion1,
	(LPVOID)NULL,
	0,&dwThreadID1);            //创建线程  Funcion1
	if (h1==NULL) printf("Thread1 create FAIL!\n");
	else printf("Thread1 create Success!\n");

	h2=CreateThread((LPSECURITY_ATTRIBUTES)NULL,
	0,
	(LPTHREAD_START_ROUTINE)Funcion2,
	(LPVOID)NULL,  
	0,&dwThreadID2);           //创建线程  Funcion2
	if (h2==NULL) printf("Thread2 create FAIL!\n");
	else printf("Thread2 create Success!\n");

	Sleep(1000);
	CloseHandle(h1);
	CloseHandle(h2);
	ExitThread(0);
	return nRetCode;
}

void Funcion1()
{ 
	int r1;
	WaitForSingleObject(hMutex, INFINITE);
	r1=count;
	Sleep(500);
	r1=r1+1;
	count=r1;
	printf("count in Funcion1=%d\n",count);
	ReleaseMutex(hMutex);
}

void Funcion2()
{ 
	int r2;
	WaitForSingleObject(hMutex, INFINITE);
	r2=count;
	Sleep(1000);
	r2=r2+1;
	count=r2;
	printf("count in Funcion2=%d\n",count);
	ReleaseMutex(hMutex);
}

四、实验结果与总结

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

image

image


实验二:
   能正确的使用互斥对象(Mutex),包括互斥对象(Mutex)包括创建互斥对象(CreateMutex())、打开互斥对象(OpenMutex())及释放互斥对象(ReleaseMutex())API函数。进一步理解线程的互斥。
  

image

image

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
信号量是一种用于协调并发进程之间共享资源的机制。在信号量机制中,通常使用两种操作:wait() 和 signal()。 wait() 操作会尝试获取一个互斥信号量,如果该信号量的值为 0,那么该进程就会被阻塞,直到该信号量的值大于 0(即有其他进程释放了该信号量),然后才能继续执行。如果该信号量的值大于 0,那么该进程就可以继续执行,并将该信号量的值减 1。 signal() 操作会释放一个互斥信号量,将该信号量的值加 1。如果有其他进程正在等待该信号量,那么其中的一个进程就会被唤醒,并获得该信号量。 在实现进程互斥时,通常会使用一个互斥信号量来控制对共享资源的访问。当一个进程需要访问共享资源时,它会使用 wait() 操作来获取该互斥信号量。如果此时该信号量的值为 0,那么该进程就会被阻塞,直到其他进程释放了该信号量。当该进程访问完共享资源后,它会使用 signal() 操作来释放该互斥信号量,让其他进程可以访问该共享资源。 wait() 和 signal() 操作必须成对出现,否则就会导致死锁或者资源泄露等问题。例如,如果一个进程在使用 wait() 操作获取互斥信号量之后,没有使用 signal() 操作释放该信号量,那么其他进程就永远无法获取该信号量,导致死锁。因此,wait() 和 signal() 操作必须成对出现,以确保共享资源能够正确地被访问和释放。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

司马道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值