互斥体的使用
什么是信号?
所谓的信号,就类似于自身的一个状态,而等待函数(即WaitForSingleObject)就是检查这个状态,假如状态为FALSE,也叫没有信号或者非激发态,那么等待函数就会等待下去。假如状态为TRUE,也叫做有信号或者激发态,那么等待函数就会返回。当线程结束的时候,就会由没有信号变为有信号的状态,由此,WaitForSingleObject()就能够等到线程结束再返回,去执行后面的代码。不光线程是可以等待,还有很多的内核对象都是可以等待的
对于互斥体,有三个内容非常重要:
- 它有两个状态,激发态和非激发态。
- 它有一个概念,叫做线程拥有权,与临界区相类似。
- 等待函数等待互斥体的副作用,将互斥体的拥有者设置为本线程,将互斥体的状态设置为非激发态。
于是一般情况下,出现了下面的情况:
- 当互斥体没有被任何一个线程拥有时,她处于激发态,也可以说锁是打开的
- 当一个线程A调用了WaitForSingleObject()时,WaitForSingleObject()函数会立即返回,并将互斥体设置为非激发态,互斥体就被锁住了,此线程获得拥有权
- 后面的时刻,任何其他调用 WaitForSingleObject()函数的线程无法获得线程的拥有权,必须一直等待互斥体,他们全部被阻塞
- 当线程A调用ReleaseMutex()函数,将互斥体释放,即为互斥体解锁,此时互斥体不被任何一个线程拥有,并被设置为激发态,会等待它的线程中随机选择一个重复最开始的情况
互斥体同一时刻只能被一个线程拥有,在WaitForSingleObject()和ReleaseMutex()函数之间的代码被保护了起来,就像在临界区内一样。所不同的是,互斥体是一个内核对象,使得其能够在多个进程间进行同步。
相比于临界区的另外一个优势是,当互斥体的线程意外崩溃,没有调用ReleaseMutex(),互斥体会自动被设置为不被任何线程拥有,并处于激发态。
互斥体的使用代码:
#include <iostream>
#include <Windows.h>
int g_n = 0;
HANDLE g_hMutex = 0;
DWORD WINAPI ThreadPro1(LPVOID lpThreadParameter) {
for (int i = 0; i < 100000; i++)
{
WaitForSingleObject(g_hMutex, -1);
g_n++;
ReleaseMutex(g_hMutex);
}
return 0;
}
DWORD WINAPI ThreadPro2(LPVOID lpThreadParameter) {
for (int i = 0; i < 100000; i++)
{
WaitForSingleObject(g_hMutex, -1);
g_n++;
ReleaseMutex(g_hMutex);
}
return 0;
}
int main() {
HANDLE hThread1 = 0, hThread2 = 0;
g_hMutex = CreateMutex(
NULL,
FALSE,//创建的线程,是不是第一个拥有者
NULL
);
hThread1 = CreateThread(NULL, NULL, ThreadPro1, NULL, NULL, NULL);
hThread2 = CreateThread(NULL, NULL, ThreadPro2, NULL, NULL, NULL);
WaitForSingleObject(hThread1, -1);
WaitForSingleObject(hThread2, -1);
printf("%d", g_n);
return 0;
}
评论区