博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows线程同步——互斥量对象
阅读量:3527 次
发布时间:2019-05-20

本文共 3293 字,大约阅读时间需要 10 分钟。

1. 概述

当两个或更多线程需要同时访问一个共享资源时,为了保证程序的正常运行,需要保证同一个资源在同一时刻只能有一个线程去访问它。Mutex 是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。

互斥量与关键段(线程同步方式)的行为完全相同,当互斥量是内核对象,而关键段是用户模式下的的同步对象。互斥量对象包含: 一个线程 ID ,使用计数和递归计数 。线程 ID 表示当前占用该互斥量的线程 ID ,递归计数表示该线程占用互斥量的次数,使用计数表示使用互斥量对象的不同线程的个数。

互斥量对象有许多用途,它是使用最为频繁的内核对象之一,一般用来对多个进程访问同一块内存进行同步。

2. 互斥量相关API

2.1 CreateMutex()函数

HANDLE WINAPI CreateMutex(  _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,  _In_     BOOL                  bInitialOwner,  _In_opt_ LPCTSTR               lpName);

参数说明

lpMutexAttributes:互斥量安全访问属性,一般置为 NULL ;

bInitialOwner:控制互斥量的初始状态,一般设置为 false ,是互斥量的线程 ID 和递归计数都设为 0 ,表示互斥量不被任何进程占用,处于触发状态,其他进程可以进行调用等待函数,获得该互斥量对象,获得对同步资源的占用。如果初始值设为 true ,互斥量的线程 ID 设置为当前线程,递归计数设为 1 ,表示当前线程占用互斥量对象,拥有对同步资源的独占,互斥量处于未触发状态。
lpName:用于创建有名的内核对象,即用来创建跨进程边界的内核对象。

CreateMutex 用于创建名为 lpName 的互斥量内核对象,并返回指向该内核对象的句柄。如果该内核对象已经存在,那么 CreateMutex 会返回该内核对象的句柄,并通过系统返回错误 ERROR_ALREADY_EXISTS ,通过 GetLastError ()获得。

2.2 OpenMutex()函数

HANDLE WINAPI OpenMutex(  _In_ DWORD   dwDesiredAccess,  _In_ BOOL    bInheritHandle,  _In_ LPCTSTR lpName);

参数说明

dwDesiredAccess:对互斥量对象访问权限的设置, MUTEX_ALL_ACCESS  请求对互斥体的完全访问, MUTEX_MODIFY_STATE  允许使用  ReleaseMutex  函数, SYNCHRONIZE  允许互斥体对象同步使用;

bInheritHandle:是否希望子进程继承互斥量对象的句柄,一般设置为false ;
lpName:要打开的互斥量对象的名称;

OpenMutex 用于打开已经存在的互斥量对象,若打开成功,则返回指向该内核对象的句柄,否则返回 NULL 。可以使用 CreateMutex 来实现打开功能。

2.3 WaitForSingleObject()函数

DWORD WINAPI WaitForSingleObject(  _In_ HANDLE hHandle,  _In_ DWORD  dwMilliseconds);

参数说明

hHandle :指向内核对象的句柄;

dwMilliseconds:线程最大等待多长时间,直到该对象被触发。经常使用INFINITE ,表示阻塞等待。

WaitForSingleObject被称呼为等待函数,是等待内核对象被触发通用的等待函数,被用在所有的内核对象触发等待中。等待函数在等待互斥量内核对象时,会进行互斥量的线程ID 是否为 0 ,如果为非 0 ,表示互斥量处于未触发状态,等待函数会被阻塞。当另外一个线程将互斥量释放,使其线程 ID 为 0 时,系统会唤醒阻塞的等待函数,把互斥量的线程 ID 设置为它的线程 ID ,使其成为可调度状态 。

还有一个WaitForMultipleObject函数,用于等待多个内核对象被触发。

2.4 ReleaseMutex() 函数

BOOL WINAPI ReleaseMutex(  _In_ HANDLE hMutex);

参数说明

hMutex:互斥量内核对象的句柄;

当一个线程访问完通过互斥量对象获得的独占资源后,应该调用ReleaseMutex,使互斥量恢复为未触发状态。即设置互斥量对象的线程ID 和递归计数为 0 ,当递归计数大于 1 时,还有进行对应多次的 ReleaseMutex 。

3. 示例代码

DWORD WINAPI my_thread1(LPVOID m_pParameter);	//用户线程1DWORD WINAPI my_thread2(LPVOID m_pParameter);	//用户线程2UINT count = 0;									//全局的计数函数HANDLE m_hMutex;								//定义一个互斥量句柄int _tmain(int argc, _TCHAR* argv[]){	system("color f0");	int count_size(50);	m_hMutex = ::CreateMutex(NULL, false, NULL);		//初始化互斥量	HANDLE m_h1 = CreateThread(NULL, NULL, my_thread1, &count_size, NULL, NULL);	//用户线程1	HANDLE m_h2 = CreateThread(NULL, NULL, my_thread2, &count_size, NULL, NULL);	//用户线程2	::WaitForSingleObject(m_h1, INFINITE);	//等待子线程结束	::WaitForSingleObject(m_h2, INFINITE);	//等待子线程结束	::CloseHandle(m_hMutex);			//关闭句柄	::CloseHandle(m_h1);	::CloseHandle(m_h2);	system("pause");	return 0;}//用户线程1DWORD WINAPI my_thread1(LPVOID m_pParameter){	UINT* my_count = (UINT*)m_pParameter;	cout << "thread1" << endl;	for (int i = 0; i < *my_count; ++i)	{		::WaitForSingleObject(m_hMutex, INFINITE);	//等待互斥量		count = i;		cout << count << "\t";		::ReleaseMutex(&m_hMutex);					//释放互斥量	}	return 0;}//用户线程2DWORD WINAPI my_thread2(LPVOID m_pParameter){	UINT* my_count = (UINT*)m_pParameter;	cout << "thread2" << endl;	for (int i = 0; i < *my_count; ++i)	{		::WaitForSingleObject(m_hMutex, INFINITE);	//等待互斥量		count = i;		cout << count << "\t";		::ReleaseMutex(&m_hMutex);					//释放互斥量	}	return 0;}

转载地址:http://gfkhj.baihongyu.com/

你可能感兴趣的文章
最短路径最基本的三种算法【此后无良辰】
查看>>
class的点点滴滴的总结
查看>>
vector 的点点滴滴的总结
查看>>
测试用例
查看>>
自动化测试学习步骤
查看>>
自动化测试需要掌握的知识
查看>>
HTTP协议
查看>>
Python问题总结01
查看>>
Python小程序——冒泡排序
查看>>
cmd中输入net start mysql 提示:服务名无效或者MySQL正在启动 MySQL无法启动
查看>>
LeetCode 206反转链表 [javsScript]
查看>>
[LeetCode javaScript] 3. 无重复字符的最长子串
查看>>
[LeetCode javaScript] 6. Z字形变换
查看>>
[LeetCode javaScript]455. 分发饼干
查看>>
[LeetCode javaScript] 735. 行星碰撞
查看>>
[LeetCode javaScript] 125. 验证回文串
查看>>
[LeetCode javaScript] 226. 翻转二叉树
查看>>
[LeetCode javaScript] 520. 检测大写字母
查看>>
[LeetCode javaScript] 350. 两个数组的交集 II
查看>>
[LeetCode javaScript] 53.最大子序和
查看>>