Windows 内核对象(六) 信号量和互斥体
信号量
我们有时候, 会有控制程序的启动次数的需求
这就用到我们的信号量(Semaphore)内核对象.
可以使用CreateSemaphore创建一个信号量
也可以使用OpenSemaphore打开一个信号量
- 信号量有一个
计数属性 它会决定这个信号量能够被Wait多少次
- 每Wait一次, 计数减一
- 当计数为0时, Wait将被阻塞
CreateSemaphore
HANDLE WINAPI CreateSemaphore(
_In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
_In_ LONG lInitialCount,
_In_ LONG lMaximumCount,
_In_opt_ LPCTSTR lpName
);lpSemaphoreAttributes
- 安全属性
- 一般设置为NULL
lInitialCount
- 初始化的时候的计数
lMaximumCount
- 最大的计数
lpName
- 信号量的名称
- 打开的时候需要使用到
- 可以传递NULL创建匿名信号量
示例
#include <Windows.h>
#include <tchar.h>
INT _tmain()
{
// ==============================================================
{
// 初始计数为0, 最大计数为5
HANDLE hSemaphore = CreateSemaphore(NULL, 0, 5, TEXT("HadesSem"));
// OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, TEXT("HadesSem"));
// 此时, 因为计数是 0 , 所以程序被阻塞
WaitForSingleObject(hSemaphore, INFINITE);
CloseHandle(hSemaphore);
}
// ==============================================================
// ==============================================================
{
// 初始计数为0, 最大计数为5
HANDLE hSemaphore = CreateSemaphore(NULL, 2, 5, TEXT("HadesSem"));
WaitForSingleObject(hSemaphore, INFINITE);
WaitForSingleObject(hSemaphore, INFINITE);
// 此时, 因为计数是 2 , 所以程序被阻塞
WaitForSingleObject(hSemaphore, INFINITE);
CloseHandle(hSemaphore);
}
// ==============================================================
// ==============================================================
{
// 初始计数为0, 最大计数为5
HANDLE hSemaphore = CreateSemaphore(NULL, 2, 5, TEXT("HadesSem"));
// 使用ReleaseSemaphore来释放/增加计数
// 最后一个参数是输出参数, 输出累加之前的数
// 现在是初始2个计数, 累加2个, 所以现在是4个计数
ReleaseSemaphore(hSemaphore, 2, NULL);
WaitForSingleObject(hSemaphore, INFINITE);
WaitForSingleObject(hSemaphore, INFINITE);
WaitForSingleObject(hSemaphore, INFINITE);
WaitForSingleObject(hSemaphore, INFINITE);
// 此时, 因为计数是 4 , 所以程序被阻塞
WaitForSingleObject(hSemaphore, INFINITE);
CloseHandle(hSemaphore);
}
// ==============================================================
// ==============================================================
{
// 初始计数为0, 最大计数为5
HANDLE hSemaphore = CreateSemaphore(NULL, 2, 5, TEXT("HadesSem"));
// 使用ReleaseSemaphore来释放/增加计数
// 最后一个参数是输出参数, 输出累加之前的数
// 现在是初始2个计数, 累加4个, 所以现在是6个计数
// 但是我们最大是 5个 所以函数执行失败
// 计数还是2
ReleaseSemaphore(hSemaphore, 4, NULL);
WaitForSingleObject(hSemaphore, INFINITE);
WaitForSingleObject(hSemaphore, INFINITE);
// 此时, 因为计数是 2 , 所以程序被阻塞
WaitForSingleObject(hSemaphore, INFINITE);
CloseHandle(hSemaphore);
}
// ==============================================================
return 0;
}互斥体
在互斥体内核对象中, 会有一个线程ID
线程ID会决定互斥体的信号状态
- 当线程ID为0时, 它处于有信号状态
- 当互斥体激活后, 它将线程ID绑定
- 此时, 它就变成了无信号状态
- 需要注意的是, 当线程ID不为0时, 对应绑定的线程是不会被wait阻塞的
互斥体还会有一个
等待计数- 每一次Wait, 都会使
等待计数递增 - 每一次 Release, 都会使
等待计数递减 - 注意, 在其他线程Release是没有用的, 必须是
拥有者(也就是调用Wait的线程)进行Release
- 每一次Wait, 都会使
如果互斥体的线程消亡, 互斥体变为遗弃状态
- 它会清理自己的线程ID为0
- 会将
等待计数清零 - 会将自己置为
有信号状态
CreateMutex
HANDLE WINAPI CreateMutex(
_In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,
_In_ BOOL bInitialOwner,
_In_opt_ LPCTSTR lpName
);lpMutexAttributes
- 安全属性
- 一般是NULL
bInitialOwner
- 是否初始化拥有者
- TRUE 将创建Mutex的线程ID保存
- FALSE 不报错
- 一般我们都传递FALSE
lpName
- 名称
- 在打开的时候使用
- 传递NULL则创建匿名互斥体
创建时设置拥有者的示例
#include <Windows.h>
#include <process.h>
#include <tchar.h>
HANDLE g_hMutex = INVALID_HANDLE_VALUE;
UINT WINAPI ThreadFunc(LPVOID lParam)
{
while (WaitForSingleObject(g_hMutex, INFINITE) == WAIT_OBJECT_0)
_tprintf(TEXT("Thread is runing....\n"));
return 0;
}
INT _tmain()
{
// 无信号的互斥体
g_hMutex = CreateMutex(NULL, TRUE, NULL);
// 这里将不会阻塞
// 因为, 我们当前线程是创建互斥体的线程
// 它拥有了当前互斥体的所有权限
// 无论怎么Wait, 都不会阻塞
WaitForSingleObject(g_hMutex, INFINITE);
WaitForSingleObject(g_hMutex, INFINITE);
WaitForSingleObject(g_hMutex, INFINITE);
WaitForSingleObject(g_hMutex, INFINITE);
WaitForSingleObject(g_hMutex, INFINITE);
WaitForSingleObject(g_hMutex, INFINITE);
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, NULL);
// 释放互斥体
// 不释放, 线程将等待
// 注释掉下面一句代码观察情况
ReleaseMutex(g_hMutex);
WaitForSingleObject(hThread, INFINITE);
return 0;
}创建时不设置拥有者的示例
等待一次的互斥体
#include <Windows.h>
#include <process.h>
#include <tchar.h>
HANDLE g_hMutex2 = INVALID_HANDLE_VALUE;
UINT WINAPI ThreadFunc2(LPVOID lParam)
{
while (WaitForSingleObject(g_hMutex2, INFINITE) == WAIT_OBJECT_0)
_tprintf(TEXT("Thread is runing....\n"));
return 0;
}
INT _tmain()
{
// 有信号的互斥体
g_hMutex2 = CreateMutex(NULL, FALSE, NULL);
// 这里将不会阻塞
WaitForSingleObject(g_hMutex2, INFINITE);
// 但是在之后, 我们的互斥体就会阻塞了
// 所以要进行Release
ReleaseMutex(g_hMutex2);
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc2, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
return 0;
}等待多次的互斥体
#include <Windows.h>
#include <process.h>
#include <tchar.h>
HANDLE g_hMutex2 = INVALID_HANDLE_VALUE;
UINT WINAPI ThreadFunc2(LPVOID lParam)
{
while (WaitForSingleObject(g_hMutex2, INFINITE) == WAIT_OBJECT_0)
_tprintf(TEXT("Thread is runing....\n"));
return 0;
}
INT _tmain()
{
// 有信号的互斥体
g_hMutex2 = CreateMutex(NULL, FALSE, NULL);
// 这里将不会阻塞
WaitForSingleObject(g_hMutex2, INFINITE);
WaitForSingleObject(g_hMutex2, INFINITE);
WaitForSingleObject(g_hMutex2, INFINITE);
WaitForSingleObject(g_hMutex2, INFINITE);
WaitForSingleObject(g_hMutex2, INFINITE);
// 但是在之后, 我们的互斥体就会阻塞了
// 所以要进行Release
// 我们Wait了多次, 所以要Release相应次数
ReleaseMutex(g_hMutex2);
ReleaseMutex(g_hMutex2);
ReleaseMutex(g_hMutex2);
ReleaseMutex(g_hMutex2);
ReleaseMutex(g_hMutex2);
ReleaseMutex(g_hMutex2);
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc2, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
return 0;
}未完待续...
如有错误,请提出指正!谢谢.
本文由 花心胡萝卜 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: 2017-07-06 at 06:24 am