1. 程式人生 > >多執行緒同步-互斥物件(深入理解Mutex)

多執行緒同步-互斥物件(深入理解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
Creates or opens a named or unnamed mutex object.
Creates or opens a named or unnamed mutex object and returns a handle to the object.
Opens an existing named mutex object.
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}