关于互斥量的基本概念:百度百科互斥量
推荐参考博客:秒杀多线程第七篇 经典线程同步 互斥量Mutex
注意:互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问。互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源 本文地址
主要用到2个函数:CreateMutex,ReleaseMutex:
CreateMutex
函数功能:创建互斥量(注意与事件Event的创建函数对比)
函数原型:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTESlpMutexAttributes,
BOOLbInitialOwner,
LPCTSTRlpName
);
第一个参数:表示安全控制,一般直接传入NULL。
第二个参数:用来确定互斥量的初始拥有者。如果传入TRUE表示互斥量对象内部会记录创建它的线程的线程ID号并将递归计数设置为1,由于该线程ID非零,所以互斥量处于未触发状态。如果传入FALSE,那么互斥量对象内部的线程ID号将设置为NULL,递归计数设置为0,这意味互斥量不为任何线程占用,处于触发状态。
第三个参数:用来设置互斥量的名称,在多个进程中的线程就是通过名称来确保它们访问的是同一个互斥量。
返回值:成功则返回一个表示互斥量的句柄,失败返回NULL。
ReleaseMutex
功能:释放互斥量
函数原型:
BOOL ReleaseMutex (HANDLEhMutex)
函数说明:
访问互斥资源前应该要调用等待函数,结束访问时就要调用ReleaseMutex()来表示自己已经结束访问,其它线程可以开始访问了。
另外还有个函数OpenMutex 可以打开其它进程中创建的互斥量
注意:主线程不要忘了删除互斥量
下面从一个例子说明:假设有三个线程都需要使用打印机,我们可以使用互斥量来控制,这样就可以保证每次只有一个线程在使用打印机
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#include<string>
#include<iostream>
#include<process.h>
#include<windows.h>
using
namespace
std;
//声明互斥量句柄
HANDLE
hmu;
//线程绑定的函数返回值和参数是确定的,而且一定要__stdcall
unsigned __stdcall threadFun(
void
*param)
{
WaitForSingleObject(hmu, INFINITE);
//等待互斥量
cout<<*(string *)(param)<<endl;
ReleaseMutex(hmu);
//释放互斥量
return
1;
}
int
main()
{
//创建互斥量
hmu = CreateMutex(NULL, FALSE, NULL);
HANDLE
hth1, hth2, hth3;
string s1 =
"first"
, s2 =
"second"
, s3 =
"third"
;
//创建线程
hth1 = (
HANDLE
)_beginthreadex(NULL, 0, threadFun, &s1, 0, NULL);
hth2 = (
HANDLE
)_beginthreadex(NULL, 0, threadFun, &s2, 0, NULL);
hth3 = (
HANDLE
)_beginthreadex(NULL, 0, threadFun, &s3, 0, NULL);
//等待子线程结束
WaitForSingleObject(hth1, INFINITE);
WaitForSingleObject(hth2, INFINITE);
WaitForSingleObject(hth3, INFINITE);
//一定要记得关闭线程句柄
CloseHandle(hth1);
CloseHandle(hth2);
CloseHandle(hth3);
//千万别忘了删除互斥量
CloseHandle(hmu);
}
|
互斥量有没有和临界区一样具有所有权属性呢,我们也从相同的例子来看:编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#include<string>
#include<iostream>
#include<process.h>
#include<windows.h>
using
namespace
std;
//声明3个互斥量句柄
HANDLE
hmu1, hmu2, hmu3;
//线程绑定的函数返回值和参数是确定的,而且一定要__stdcall
unsigned __stdcall threadFunA(
void
*)
{
for
(
int
i = 0; i < 10; i++){
WaitForSingleObject(hmu1, INFINITE);
//等待互斥量
cout<<
"A"
;
ReleaseMutex(hmu2);
//释放互斥量
}
return
1;
}
unsigned __stdcall threadFunB(
void
*)
{
for
(
int
i = 0; i < 10; i++){
WaitForSingleObject(hmu2, INFINITE);
//等待互斥量
cout<<
"B"
;
ReleaseMutex(hmu3);
//释放互斥量
}
return
2;
}
unsigned __stdcall threadFunC(
void
*)
{
for
(
int
i = 0; i < 10; i++){
WaitForSingleObject(hmu3, INFINITE);
//等待互斥量
cout<<
"C"
;
ReleaseMutex(hmu1);
//释放互斥量
}
return
3;
}
int
main()
{
hmu1 = CreateMutex(NULL, FALSE, NULL);
hmu2 = CreateMutex(NULL, FALSE, NULL);
hmu3 = CreateMutex(NULL, FALSE, NULL);
HANDLE
hth1, hth2, hth3;
//创建线程
hth1 = (
HANDLE
)_beginthreadex(NULL, 0, threadFunA, NULL, 0, NULL);
hth2 = (
HANDLE
)_beginthreadex(NULL, 0, threadFunB, NULL, 0, NULL);
hth3 = (
HANDLE
)_beginthreadex(NULL, 0, threadFunC, NULL, 0, NULL);
//等待子线程结束
WaitForSingleObject(hth1, INFINITE);
WaitForSingleObject(hth2, INFINITE);
WaitForSingleObject(hth3, INFINITE);
//一定要记得关闭线程句柄
CloseHandle(hth1);
CloseHandle(hth2);
CloseHandle(hth3);
//删除互斥量
CloseHandle(hmu1);
CloseHandle(hmu2);
CloseHandle(hmu3);
}
|
从结果看互斥量也具有所有权属性,即拥有互斥量的线程可以重复进入互斥量保护的区域