多线程同步-互斥对象(深入理解Mutex)

多线程之线程同步Mutex (功能与Critial Sections相同,但是属于内核对象,访问速度较慢,可以被不同进程调用)

一 Mutex
    互斥对象(mutex)内核对象能够确保线程拥有对单个资源的互斥访问权。实际上互斥对象是因此而得名的。互斥对象包含一个使用数量一个线程ID和一个递归计数器。
    互斥对象的行为特性与关键代码段相同,但是互斥对象属于内核对象,而关键代码段则属于用户方式对象。这意味着互斥对象的运行速度比关键代码段要慢。但是这也意味着不同进程中的多个线程能够访问单个互斥对象,并且这意味着线程在等待访问资时可以设定一个超时值。

    ID用于标识系统中的哪个线程当前拥有互斥对象,递归计数器用于指明该线程拥有互斥对象的次数。
    互斥对象有许多用途,属于最常用的内核对象之一。通常来说,它们用于保护由多个线程访问的内存块。如果多个线程要同时访问内存块,内存块中的数据就可能遭到破坏。互斥对象能够保证访问内存块的任何线程拥有对该内存块的独占访问权,这样就能够保证数据的完整性。

互斥对象的使用规则如下:

? 如果线程ID是0(这是个无效ID),互斥对象不被任何线程所拥有,并且发出该互斥对象的通知信号。

? 如果ID是个非0数字,那么一个线程就拥有互斥对象,并且不发出该互斥对象的通知信号。

? 与所有其他内核对象不同, 互斥对象在操作系统中拥有特殊的代码,允许它们违反正常的规则。

若要使用互斥对象,必须有一个进程首先调用CreateMutex,以便创建互斥对象:
HANDLECreateMutex(
   PSECURITY_ATTRIBUTES psa,
   BOOL fInitialOwner,
   PCTSTR pszName);
 InitialOwner参数用于控制互斥对象的初始状态。如果传递FALSE(这是通常情况下传递的值),那么互斥对象的ID和递归计数器均被设置为0。这意味着该互斥对象没有被任何线程所拥有,因此要发出它的通知信号。
如果为fInitialOwner参数传递TRUE,那么该对象的线程ID被设置为调用线程的ID,递归计数器被设置为1。由于ID是个非0数字,因此该互斥对象开始时不发出通知信号。

通过调用一个等待函数,并传递负责保护资源的互斥对象的句柄,线程就能够获得对共享资源的访问权。在内部,等待函数要检查线程的ID,以了解它是否 是0(互斥对象发出通知信号)。如果线程ID是0,那么该线程ID被设置为调用线程的ID,递归计数器被设置为1,同时,调用线程保持可调度状态。

如果等待函数发现ID不是0(不发出互斥对象的通知信号),那么调用线程便进入等待状态。系统将记住这个情况,并且在互斥对象的ID重新设置为0 时,将线程ID设置为等待线程的ID,将递归计数器设置为1,并且允许等待线程再次成为可调度线程。与所有情况一样,对互斥内核对象进行的检查和修改都是 以原子操作方式进行的。

一旦线程成功地等待到一个互斥对象,该线程就知道它已经拥有对受保护资源的独占访问权。试图访问该资源的任何其他线程(通过等待相同的互斥对象)均 被置于等待状态中。当目前拥有对资源的访问权的线程不再需要它的访问权时,它必须调用ReleaseMutex函数来释放该互斥对象:
BOOL ReleaseMutex(HANDLE hMutex);
该函数将对象的递归计数器递减1。

当该对象变为已通知状态时,系统要查看是否有任何线程正在等待互斥对象。如果有,系统将“按公平原则”选定等待线程中的一个,为它赋予互斥对象的所 有权。当然,这意味着线程I D被设置为选定的线程的ID,并且递归计数器被置为1。如果没有其他线程正在等待互斥对象,那么该互斥对象将保持已通知状态,这样,等待互斥对象的下一个 线程就立即可以得到互斥对象。

二 API

Mutex function Description
CreateMutex Creates or opens a named or unnamed mutex object.
CreateMutexEx Creates or opens a named or unnamed mutex object and returns a handle to the object.
OpenMutex Opens an existing named mutex object.
ReleaseMutex Releases ownership of the specified mutex object.

三 实例
来自msdn的实例:在线程函数中有一个循环,在每个循环的开始都取得Mutex,然后对全局或静态操作,相当于在关键代码段操作,然后在使用完以后释放它,大家可以执行,查看结果

多线程(C++)同步Mutex#include <windows.h>
多线程(C++)同步Mutex#include 
<stdio.h>
多线程(C++)同步Mutex
多线程(C++)同步Mutex
#define THREADCOUNT 64  //less than 64
多线程(C++)同步MutexHANDLE ghMutex; 
多线程(C++)同步Mutex
int g_x = 0;
多线程(C++)同步Mutex
多线程(C++)同步MutexDWORD WINAPI WriteToDatabase(LPVOID);
多线程(C++)同步Mutex
多线程(C++)同步Mutex
void main()
多线程(C++)同步Mutex
{
多线程(C++)同步Mutex    HANDLE aThread[THREADCOUNT];
多线程(C++)同步Mutex    DWORD ThreadID;
多线程(C++)同步Mutex    
int i;
多线程(C++)同步Mutex
多线程(C++)同步Mutex    
// Create a mutex with no initial owner
多线程(C++)同步Mutex
    ghMutex = CreateMutex( 
多线程(C++)同步Mutex        NULL,              
// default security attributes
多线程(C++)同步Mutex
        FALSE,             // initially not owned
多线程(C++)同步Mutex
        NULL);             // unnamed mutex
多线程(C++)同步Mutex

多线程(C++)同步Mutex    
if (ghMutex == NULL) 
多线程(C++)同步Mutex    
{
多线程(C++)同步Mutex        printf(
"CreateMutex error: %d\n", GetLastError());
多线程(C++)同步Mutex        
return;
多线程(C++)同步Mutex    }

多线程(C++)同步Mutex
多线程(C++)同步Mutex    
// Create worker threads
多线程(C++)同步Mutex

多线程(C++)同步Mutex    
for( i=0; i < THREADCOUNT; i++ )
多线程(C++)同步Mutex    
{
多线程(C++)同步Mutex        aThread[i] 
= CreateThread( 
多线程(C++)同步Mutex                     NULL,       
// default security attributes
多线程(C++)同步Mutex
                     0,          // default stack size
多线程(C++)同步Mutex
                     (LPTHREAD_START_ROUTINE) WriteToDatabase, 
多线程(C++)同步Mutex                     NULL,       
// no thread function arguments
多线程(C++)同步Mutex
                     0,          // default creation flags
多线程(C++)同步Mutex
                     &ThreadID); // receive thread identifier
多线程(C++)同步Mutex

多线程(C++)同步Mutex        
if( aThread[i] == NULL )
多线程(C++)同步Mutex        
{
多线程(C++)同步Mutex            printf(
"CreateThread error: %d\n", GetLastError());
多线程(C++)同步Mutex            
return;
多线程(C++)同步Mutex        }

多线程(C++)同步Mutex    }

多线程(C++)同步Mutex
多线程(C++)同步Mutex    
// Wait for all threads to terminate
多线程(C++)同步Mutex

多线程(C++)同步Mutex    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
多线程(C++)同步Mutex
多线程(C++)同步Mutex    
// Close thread and mutex handles
多线程(C++)同步Mutex
    for( i=0; i < THREADCOUNT; i++ )
多线程(C++)同步Mutex        CloseHandle(aThread[i]);
多线程(C++)同步Mutex    CloseHandle(ghMutex);
多线程(C++)同步Mutex
多线程(C++)同步Mutex    printf(
"g_x is :%d\n",g_x);
多线程(C++)同步Mutex}

多线程(C++)同步Mutex
多线程(C++)同步MutexDWORD WINAPI WriteToDatabase( LPVOID lpParam )
多线程(C++)同步Mutex

多线程(C++)同步Mutex    DWORD dwCount
=0, dwWaitResult; 
多线程(C++)同步Mutex
多线程(C++)同步Mutex    
// Request ownership of mutex.
多线程(C++)同步Mutex

多线程(C++)同步Mutex    
while( dwCount < 100 )
多线程(C++)同步Mutex    

多线程(C++)同步Mutex        dwWaitResult 
= WaitForSingleObject( 
多线程(C++)同步Mutex            ghMutex,    
// handle to mutex
多线程(C++)同步Mutex
            INFINITE);  // no time-out interval
多线程(C++)同步Mutex
 
多线程(C++)同步Mutex        
switch (dwWaitResult) 
多线程(C++)同步Mutex        
{
多线程(C++)同步Mutex            
// The thread got ownership of the mutex
多线程(C++)同步Mutex
            case WAIT_OBJECT_0: 
多线程(C++)同步Mutex                __try 

多线程(C++)同步Mutex                    g_x
++;
多线程(C++)同步Mutex                    
// TODO: Write to the database
多线程(C++)同步Mutex
                    printf("Thread %d writing to database多线程(C++)同步Mutex\n"
多线程(C++)同步Mutex                           GetCurrentThreadId());
多线程(C++)同步Mutex                    dwCount
++;
多线程(C++)同步Mutex                }
 
多线程(C++)同步Mutex
多线程(C++)同步Mutex                __finally 

多线程(C++)同步Mutex                    
// Release ownership of the mutex object
多线程(C++)同步Mutex
                    if (! ReleaseMutex(ghMutex)) 
多线程(C++)同步Mutex                    

多线程(C++)同步Mutex                        
// Deal with error.
多线程(C++)同步Mutex
                    }
 
多线程(C++)同步Mutex                }
 
多线程(C++)同步Mutex                
break
多线程(C++)同步Mutex
多线程(C++)同步Mutex            
// The thread got ownership of an abandoned mutex
多线程(C++)同步Mutex
            case WAIT_ABANDONED: 
多线程(C++)同步Mutex                
return FALSE; 
多线程(C++)同步Mutex        }

多线程(C++)同步Mutex    }

多线程(C++)同步Mutex    
return TRUE; 
多线程(C++)同步Mutex}
阅读更多
个人分类: win32-OS
上一篇多线程同步-临界区(深入理解CRITICAL_SECTION)
下一篇WaitForSingleObject 和 WaitForMultipleObjects函数 (让线程挂起等待事件)
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭