秒杀多线程第七篇 经典线程同步 互斥量Mutex
参考博客:http://blog.csdn.net/morewindows/article/details/7470936
使用Mutex来解决资源的互斥访问
互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问。互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源。使用互斥量Mutex主要将用到四个函数。
第一个:创建互斥量
HANDLECreateMutex(
LPSECURITY_ATTRIBUTESlpMutexAttributes,
BOOLbInitialOwner,
LPCTSTRlpName
);
第一个参数:安全控制传入NULL
第二个参数:互斥量的拥有者 TRUE未触发状态 /NULL表示触发状态
第三个参数:互斥量的名字 用来确定多进程的线程访问资源时,互斥量是同一个
返回值:成功时返回互斥量句柄,失败时返回NULL
第二个:打开互斥量
HANDLEOpenMutex(
DWORDdwDesiredAccess,
BOOLbInheritHandle,
LPCTSTRlpName //名称
);
第一个参数:访问权限一般设置为MUTEX_ALL_ACCESS
第二个参数:互斥量句柄的传承性 一般设置为TRUE
第三个参数:互斥量的名称 进程中的线程可以通过这个名称来访问互斥量
第三个:触发互斥量
BOOLReleaseMutex (HANDLEhMutex)
访问互斥资源前应该要调用等待函数,结束访问时就要调用ReleaseMutex()来表示自己已经结束访问,其它线程可以开始访问了
第四个:清理互斥量
CloseHandle()
每个内核函数都可以用CloseHandle()来清理
单独使用互斥量编写代码
#include <stdio.h>#include <process.h>#include <windows.h>//定义事件句柄
HANDLE g_hThreadMutex;//定义CS段
CRITICAL_SECTION g_csThreadCode;long g_num; //登录次数unsigned int __stdcall Fun(void *pPM); //线程函数const DWORD THREAD_NUM = 10;//启动线程数unsigned int __stdcall Fun(void *pPM){//由于创建线程是要一定的开销的,所以新线程并不能第一时间执行到这来
int nThreadNum = *(int *)pPM; //子线程获取参数//EnterCriticalSection(&g_csThreadCode);//进入关键段
ReleaseMutex(g_hThreadMutex);Sleep(50);//some work should to do
g_num++; //处理全局资源
Sleep(0);//some work should to do
printf("线程编号为%d 全局资源值为%d\n", nThreadNum, g_num);
//LeaveCriticalSection(&g_csThreadCode); //出关键段
return 0;
}int main()
{printf(" 互斥量Mutex的使用\n");
g_num = 0;g_hThreadMutex=CreateMutex(NULL,FALSE,NULL); //创建互斥量
//InitializeCriticalSection(&g_csThreadCode); //初始化关键段
HANDLE handle[THREAD_NUM];int i=0;
while (i<THREAD_NUM)
{handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);i++;WaitForSingleObject(g_hThreadMutex,INFINITE);//2.等待事件被触发
}WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);//DeleteCriticalSection(&g_csThreadCode); //销毁关键段
for (i=0;i<THREAD_NUM;i++)
CloseHandle(handle[i]);return 0;
}
运行结果为:
为什么单独使用并不能解决对资源的保护?
如果把注释的关键段CS去掉
运行结果为:
此时实现了对资源的保护(互斥量的优势在于多进程间对资源的保护)
由于互斥量常用于多进程之间的线程互斥,所以它比关键段还多一个很有用的特性——“遗弃”情况的处理。比如有一个占用互斥量的线程在调用ReleaseMutex()触发互斥量前就意外终止了(相当于该互斥量被“遗弃”了),那么所有等待这个互斥量的线程是否会由于该互斥量无法被触发而陷入一个无穷的等待过程中了?这显然不合理。因为占用某个互斥量的线程既然终止了那足以证明它不再使用被该互斥量保护的资源,所以这些资源完全并且应当被其它线程来使用。因此在这种“遗弃”情况下,系统自动把该互斥量内部的线程ID设置为0,并将它的递归计数器复置为0,表示这个互斥量被触发了。然后系统将“公平地”选定一个等待线程来完成调度(被选中的线程的WaitForSingleObject()会返回WAIT_ABANDONED_0)