CRITICAL_SECTION | Mutex |
InitializeCriticalSection() | CreateMutex() |
OpenMutex() | |
EnterCriticalSection() | WaitForSingleObject() |
WaitForMultipleObjects() | |
MsgWaitForMultipleObjects() | |
LeaveCriticalSection() | ReleaseMutex() |
DeleteCriticalSection() | CloseHandle() |
1. 创建Mutex
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner, // TRUE:条用CreateMutex的线程拥有产生出来的Mutex
LPCTSTR lpName // Mutex名称, 其他进程或线程可以通过名称使用该Mutex
// NULL Mutex没有名称
);
返回值:
调用成功,返回Mutex句柄handle,此时调用GetLastError如果返回值为ERROR_ ALREADY_EXISTS,则说明该命名的Mutex已经存在;
调用失败,返回NULL,此时GetLastError可以获得具体失败原因。
当你不再需要一个 mutex时,你可以调用CloseHandle()将它关闭.和其他核心对象一样,mutex有一个引用计数(reference count)。每次你调用CloseHandle(),引用计数便减 1。当引用计数达到 0 时, mutex 便自动被系统清除掉。
2. 锁住一个互斥器(Mutex)
欲获得一个mutex的拥有权,请使用 Win32 的 Wait...() 函数。 Wait...()对 mu tex 所做的事情和 EnterCriticalSection() 对 critical section 所做的事情差不多。
以下是获取两个Mutex的拥有权方式:
HANDLE hMutex[2]; // 假设已经创建好
方法一:
WaitForSingleObject(hMutex[0], INFINITE);
WaitForSingleObject(hMutex[1], INFINITE);
这是不安全的用法, 因为在执行完成第一行之后, 可能发生线程切换,因而产生死锁。正确应该如方法2,要么两个一起拥有,要么一个都不用有。
方法二:
WaitForMultipleObjects(hMutex, 2, INFINITE);
3. 释放Mutex拥有权
BOOL ReleaseMutex( HANDLE hMutex );
线程拥有mutex 就好像线程进入critical section 一样。一次只能有一个线程拥有该mutex。
如果线程拥有一个mutex 而在结束前没有调用 ReleaseMutex(), mutex不会被摧毁。取而代之的是,该 mutex会被视为 " 未被拥有 " 以及 " 未被激发 " ,而下一个等待中的线程会被以WAIT_ABANDONED_0 通知。不论线程是因为 ExitThread() 而结束,或是因当掉而结束,这种情况都存在。如果其他线程正以 WaitForMultipleObjects() 等待此 mutex,该函数也会返回,传回值介于 WAIT_ABANDONED_0 和 (WAIT_ABANDONED_0_n +1)之间,其中的 n 是指 handle 数组的元素个数。线程可以根据这个值了解到究竟哪一个mutex被放弃了。至于WaitForSingleObject(),则只是传回WAIT_ABANDONED_0。
4. 解决CRITICAL_SECTION的死锁问题
任何时候只要你想锁住超过一个以上的同步对象,你就有死锁的潜在病因。如果总是在相同时间把所有对象都锁住,问题可去矣。
#0001 struct Node
#0002 {
#0003 struct Node *next;
#0004 int data;
#0005 };
#0006
#0007 struct List
#0008 {
#0009 struct Node *head;
#0010 HANDLE hMutex;
#0011 };
#0012
#0013 struct List *CreateList()
#0014 {
#0015 List *list = (List *)malloc(sizeof(struct List));
#0016 list->head = NULL;
#0017 list->hMutex = CreateMutex(NULL, FALSE, NULL);
#0018 return list;
#0019 }
#0020
#0021 void DeleteList(struct List *list)
#0022 {
#0023 CloseHandle(list->hMutex);
#0024 free(list);
#0025 }
#0026
#0027 void SwapLists(struct List *list, struct List *list2)
#0028 {
#0029 struct List *tmp_list;
#0030 HANDLE arrhandles[2];
#0031
#0032 arrhandles[0] = list1->hMutex;
#0033 arrhandles[1] = list2->hMutex;
#0034 WaitForMultipleObjects(2, arrHandles, TRUE, INFINITE);
#0035 tmp_list = list1->head;
#0036 list1->head = list2->head;
#0037 list2->head = tmp_list;
#0038 ReleaseMutex(arrhandles[0]);
#0039 ReleaseMutex(arrhandles[1]);
#0040 }
5. Question
5.1 Mutex能否如下使用:
Mutex能否如下使用:
void function()
{
WaitForMultipleObjects(hMutex, 1, INFINITE);
// do something
{
WaitForMultipleObjects(hMutex, 1, INFINITE);
// do something
ReleaseMutex(hMutex);
}
ReleaseMutex(hMutex);
}
以上程序会死锁吗?
5.2 Mutex解决哲学家进餐问题