实验三 线程的互斥
1.实验目的
(1) 熟练掌握Windows系统环境下线程的创建与撤销。
(2)熟悉Windows系统提供的线程互斥API。
(3)使用WIndows系统提供的线程互斥API解决实际问题。
2.实验准备知识:相关API函数介绍
临界区对象
临界区对象(CriticalSection)包括初始化临界区(InitializeCriticalSection())、进入临界区(EnterCriticalSection())、退出临界区(LeaveCriticalSection())及删除临界区(DeleteCriticalSection())等API函数。
(1)初始化临界区
IntializeCriticalSection() 用于初始化临界区对象。
原型:
IntializeCriticalSection(
LPCRITICAL_SECTION IpCriticalSection
);
参数说明:
IpCriticalSection:指出临界区对象的地址。

**返回值:**无。
用法举例:
LPCRITICAL_SECTION hCriticalSection;
CRITICAL_SECTION Critical;
hCriticalSection=&Critical;
InitializeCriticalSection(hCriticalSection);
(2)进入临界区
EnterCriticalSection()等待进入临界区的权限,当获得该权限后进入临界区。
原型:
VOID EnterCriticalSection(
LPCRITICAL_SECTION IpCriticalSection
);
参数说明:
IpCriticalSection:指出临界区对象的地址。
**返回值:**无。
用法举例:
LPCRITICAL_SECTION hCriticalSection;
CRITICAL_SECTION Critical;
hCriticalSection=&Critical;
EnterCriticalSection(hCriticalSection);
(3)退出临界区
LeaveCriticalSection()释放临界区的使用权限。
原型:
VOID LeaveCriticalSection(
LPCRITICAL_SECTION IpCriticalSection
);
参数说明:
IpCriticalSection:指出临界区对象的地址。
**返回值:**无。
用法举例:
LPCRITICAL_SECTION hCri2calSec2on;
CRITICAL_SECTION Cri2cal;
hCri2calSec2on=&Cri2cal;
LeaveCri2calSec2on(hCri2calSec2on);
(4)删除临界区
DeleteCri2calSec2on()删除与临界区有关的所有系统资源。
原型:
VOID DeleteCri2calSec2on(
LPCRITICAL_SECTION lpCri2calSec2on
);
参数说明:
lpCri2calSec2on:指出临界区对象的地址。
返回值:
该函数没有返回值。
⽤法举例:
LPCRITICAL_SECTION hCri2calSec2on;
CRITICAL_SECTION Cri2cal;
hCri2calSec2on=&Cri2cal;
DeleteCri2calSec2on(hCri2calSec2on);
互斥对象
互斥对象(Mutex)包括创建互斥对象(CreateMutex())、打开互斥对象(OpenMutex())及释
放互斥对象(ReleaseMutex())API函数。
(1)创建互斥对象
CreateMutex(0⽤于创建⼀个互斥对象。
原型:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexASributes,
BOOL bIni2alOwner,
LPCTSTR lpName
);
参数说明:
lpMutexASributes:指定安全属性,为NULL时,信号量得到⼀个,默认的安全描述符。
bIni2alOwner:指定初始的互斥对象。如果该值为TRUE并且互斥对象已经纯在,则调⽤线程获得互斥
对象的所有权,否则调⽤线程不能获得互斥对象的所有权。想要知道互斥对象是否已经存在,参⻅返回
值说明。
lpName:给出互斥对象的名字。
返回值:
互斥对象创建成功,将返回该互斥对象的句柄。如果给出的互斥对象是系统已经存在的互斥对象,将返回这个已存在互斥对象的句柄。如果失败,系统返回NULL,可以调⽤函数GetLastError()查询失败的
原因。
⽤法举例:
sta2c HANDLE hHandle1=NULL;
//常⻅⼀个名为"MutexName1"的互斥对象
hHandle1=CreateMutex(NULL,FALSE, “MutexName1”);
(2)打开互斥对象
OpenMutex()⽤于打开⼀个互斥对象。
原型:
HANDLE OpenMutex(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
参数说明:
指明系统安全属性⽀持的对互斥对象所有可能的访问。如果系统安全属性不⽀持,则不能获得对互
斥对象访问权。
(1)dwDesireAccess:指出发开后要对互斥对象进⾏何种访问,具体描述如表所示。
对互斥对象的访问种类:
访问 | 描述 |
---|---|
MUTEX_ALL_ACCESS | 可以进⾏对任何互斥对象的访问 |
SYNCHRONIZE | 使⽤等待函数 wait func2ons 等待互斥对象成为可⽤状态或使⽤ReleaseMutex()释放使⽤权,从⽽获得互斥对象的使⽤权 |
(2) bInheritHandle: 指出返回信号量的句柄是否可以继承。
(3) IpName : 给出信号量的名字。
返回值
互斥对象打开成功,将返回该互斥对象的句柄;如果失败,系统返回NULL,可以调⽤函数
GetLastError()查询失败的原因。
⽤法举例:
sta2c HANDLE hHandle1 = NULL;
//打开⼀个名为"MutexName1"的互斥对象
hHandle=OpenMutex(SYNCHRONIZE,NULL,“MutexName1”);
(3)释放互斥对象
ReleaseMutex() ⽤于释放互斥对象。
原型:
BOOL ReleaseMutex(
HANDLE hMUTEX;
);
参数说明:
hMutex:Mutex对象的句柄。CreateMutex()和OpenMutex()函数返回该句柄。
**返回值:**如果成功,将返回⼀个⾮0值;如果失败系统将返回0,可以调⽤函数 GetLastError()查询失败的原因。
⽤法举例:
sta2c HANDLE hHandle1=NULL;
BOOL rc;
rc= ReleaseMutex(hHandle1)
3.实验内容
// 1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "1.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); //创建线程 func1
if (h1==NULL) printf("Thread1 create FAIL!\n");
else printf("Thread1 create Success!\n");
h2=CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)func2, (LPVOID)NULL, 0,&dwThreadID2); //创建线程 func2
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 func2()
{
int r2;
EnterCriticalSection (hCriticalSection); //进入临界区
r2=count;
Sleep(100);
r2=r2+1;
count=r2;
printf("count in func2=%d\n",count);
LeaveCriticalSection (hCriticalSection); //退出临界区
}
void func1()
{
int r1;
EnterCriticalSection (hCriticalSection); //进入临界区
r1=count;
Sleep(500);
r1=r1+1;
count=r1;
printf("count in func1=%d\n",count);
LeaveCriticalSection (hCriticalSection); //退出临界区
}