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