由接力赛来理解互斥对象同步线程

      先看看互斥对象的函数原型:

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直到返回时的等待时间可看作运动员等待的过程。

 

以上是本人对互斥对象使用的一点薄浅认识,希望对有需要的朋友有所帮助。这也是第一次写技术文章,其中多有不足之处,希望大家指正,一定虚心接受并改正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值