先看看互斥对象的函数原型:
HANDLE WINAPI CreateMutex(
__in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
__in BOOL bInitialOwner,
__in_opt LPCTSTR lpName
);
Parameters
lpMutexAttributes
A pointer to a SECURITY_ATTRIBUTES structure. If this parameter is NULL, the handle cannot be inherited by child processes.
bInitialOwner
If this value is TRUE and the caller created the mutex, the calling thread obtains initial ownership of the mutex object. Otherwise, the calling thread does not obtain ownership of the mutex. To determine if the caller created the mutex, see the Return Values section.
lpName
The name of the mutex object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.
Return Value
If the function succeeds, the return value is a handle to the newly created mutex object.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
If the mutex is a named mutex and the object existed before this function call, the return value is a handle to the existing object, GetLastError returns ERROR_ALREADY_EXISTS, bInitialOwner is ignored, and the calling thread is not granted ownership. However, if the caller has limited access rights, the function will fail with ERROR_ACCESS_DENIED and the caller should use the OpenMutex function.
以上关于CreateMutex函数信息来自MSDN文档。这里主要解释bInitialOwner参数,如果该参数为true且调用者创建的互斥对象,那么调用CreateMutex的线程获得这个互斥对象的使用权。否则,即该参数为false或者互斥对象不是由该线程创建,那么该线程没有获得该互斥对象的使用权。
下面的例子也来自MSDN,如下所示:
#include <windows.h>
#include <stdio.h>
#define THREADCOUNT 2
HANDLE ghMutex;
DWORD WINAPI WriteToDatabase( LPVOID );
void main()
{
HANDLE aThread[THREADCOUNT];
DWORD ThreadID;
int i;
// Create a mutex with no initial owner
ghMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (ghMutex == NULL)
{
printf("CreateMutex error: %d\n", GetLastError());
return;
}
// Create worker threads
for( i=0; i < THREADCOUNT; i++ )
{
aThread[i] = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE) WriteToDatabase,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID); // receive thread identifier
if( aThread[i] == NULL )
{
printf("CreateThread error: %d\n", GetLastError());
return;
}
}
// Wait for all threads to terminate
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
// Close thread and mutex handles
for( i=0; i < THREADCOUNT; i++ )
CloseHandle(aThread[i]);
CloseHandle(ghMutex);
}
DWORD WINAPI WriteToDatabase( LPVOID lpParam )
{
DWORD dwCount=0, dwWaitResult;
// Request ownership of mutex.
while( dwCount < 20 )
{
dwWaitResult = WaitForSingleObject(
ghMutex, // handle to mutex
INFINITE); // no time-out interval
switch (dwWaitResult)
{
// The thread got ownership of the mutex
case WAIT_OBJECT_0:
__try {
// TODO: Write to the database
printf("Thread %d writing to database...\n",
GetCurrentThreadId());
dwCount++;
}
__finally {
// Release ownership of the mutex object
if (! ReleaseMutex(ghMutex))
{
// Deal with error.
}
}
break;
// The thread got ownership of an abandoned mutex
case WAIT_ABANDONED:
return FALSE;
}
}
return TRUE;
}
假如有一个数据库,多个线程共享访问这个数据库,一次只能一个线程写入数据库。这时可以用互斥对象来保证一次只有一个线程对数据库进行写入操作。
首先定义线程对象数组,一个全局互斥对象ghMutex。ghMutex在主函数(线程)中创建,并设bInitalOwner为FALSE,然后创建线程。第二步,调用WaitForMultipleObjects函数等待线程们结束,结束后关闭线程对象和互斥对象。
这里有必要说明一下线程函数WriteToDatabase。当线程执行到dwWaitResult = WaitForSingleObject( ghMutex,INFINITE)时,线程处于等待状态,等到函数返回了,看返回结果是什么?如果是WAIT_OBJECT_0,表示该线程已经获得了互斥对象的使用权,该线程继续执行写入数据库的代码。WaitForSingleObjects其它返回值就不再细说了,这里贴出其它返回值的说明,
Return Value
If the function succeeds, the return value indicates the event that caused the function to return. It can be one of the following values.
Return code/value
Description
WAIT_ABANDONED
0x00000080L
The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
If the mutex was protecting persistent state information, you should check it for consistency.
WAIT_OBJECT_0
0x00000000L
The state of the specified object is signaled.
WAIT_TIMEOUT
0x00000102L
The time-out interval elapsed, and the object's state is nonsignaled.
可以从生活中找相似的情形。比如说接力比赛。把一场比赛看做是程序的执行过程,主线程当作第一个跑的人,互斥对象当作接力棒,其它参赛人员当作子线程,而在赛场上跑这个动作看作是访问数据库。比赛开始了,大家都想跑,但是只有等待上一个人跑完一圈了,而且你拿到接力棒后,你才能跑。对于上述例子来讲,线程都想写入数据库,只有获得互斥对象所有权的线程,才能访问数据库,线程调用WaitForSingObjects直到返回时的等待时间可看作运动员等待的过程。
以上是本人对互斥对象使用的一点薄浅认识,希望对有需要的朋友有所帮助。这也是第一次写技术文章,其中多有不足之处,希望大家指正,一定虚心接受并改正。