執行緒同步之互斥量Mutex

2021-09-25 06:20:47 字數 4531 閱讀 3426

前面的文章介紹了執行緒的建立、終止、連線和分離。本篇介紹執行緒的同步。

多執行緒的難點是對共享資源的訪問,如何保證多個執行緒能夠「同時」訪問同乙個共享資源而又不引起衝突,就是執行緒同步的本質。

互斥量用來確保共享資源同時只被乙個執行緒訪問。互斥量有兩種狀態:已鎖定(locked)和未鎖定(unlocked)。在任何時候,最多只能有乙個執行緒可以鎖定該互斥量。一旦某個執行緒鎖定互斥量,即成為該互斥量的所有者,只有所有者才能給互斥量解鎖。

互斥量分為「靜態分配互斥量」和「動態分配互斥量」兩種型別。

靜態分配的互斥量,在初始化時可將其定義為如下形式,也是我個人最常使用的一種方式:

pthread_mutex_t mutex = pthread_mutex_initializer;
靜態初始值pthread_mutex_initializer只能對經由靜態分配且攜帶預設屬性的互斥量進行初始化,其他情況下,必須呼叫pthread_mutex_init()對互斥量進行動態初始化。

#include int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);  // return 0 on success, or a positive error number on error
引數mutex是初始化操作的目標互斥量;引數attr是指向pthread_mutexattr_t型別物件的指標,該物件在函式呼叫之前已經過了初始化處理,用於定義互斥量的屬性。若將attr引數置為null,則該互斥量的各種屬性會取預設值。

那麼,在哪些情況下,需要呼叫pthread_mutex_init()來初始化互斥量呢?

(1) 動態分配在堆中的互斥量。例如,動態建立針對某一結構的鍊錶,表中每個結構都包含乙個pthread_mutex_t型別的字段來存放互斥量,用以保護對該結構的訪問。

(2) 互斥量是在棧中分配的自動變數。

(3) 初始化由靜態分配,且不使用預設屬性的互斥量。

當不再需要由自動或動態分配的互斥量時,應使用pthread_mutex_destroy()將其銷毀。對於由pthread_mutex_initializer靜態初始化的互斥量,則無需呼叫pthread_mutex_destroy()。

#include int pthread_mutex_destroy(pthread_mutex_t *mutex); // return 0 on success, or a positive error number on error
銷毀互斥量需要注意的幾點:

(1) 互斥量處於未鎖定狀態,且後續也無任何執行緒企圖鎖定它時,才可以銷毀;

(2) 若互斥量處於動態分配的一塊記憶體區域內,應在釋放此記憶體前將互斥量銷毀;

(3) 對於自動分配的互斥量,應在宿主函式返回前將其銷毀。

經由pthread_mutex_destroy()銷毀的互斥量,可呼叫pthread_mutex_init()對其重新初始化。

互斥量的型別屬於互斥量的屬性之一。susv3定義了3種互斥量型別:

下里演示了如何設定互斥量型別、互斥量的動態初始化等操作:

pthread_mutex_t mutex;

pthread_mutexattr_t mutex_attr;

int ret, type;

ret = pthread_mutexattr_init(&mutex_attr);

if(ret != 0)

ret = pthread_mutexattr_settype(&mutex_attr, pthread_mutex_errorcheck);

if(ret != 0)

ret = pthread_mutex_init(&mutex, &mutex_attr);

if(ret != 0)

ret = pthread_mutexattr_destroy(&mutex_attr);

if(ret != 0)

互斥量在被初始化之後,處於未鎖定狀態。可分別通過pthread_mutex_lock()和pthread_mutex_unlock()將其加鎖和解鎖。

#include int pthread_mutex_lock(pthread_mutex_t *mutex);   //return 0 on success, or a positive error number on error

int pthread_mutex_unlock(pthread_mutex_t *mutex); //return 0 on success, or a positive error number on error

在呼叫pthread_mutex_lock()時需要傳入要鎖定的互斥量。如果該互斥量當前處於未鎖定狀態,則將其鎖定並立即返回;如果該互斥量當前被其他執行緒鎖定,那麼pthread_mutex_lock()將會一直被阻塞直到互斥量被其他執行緒解鎖,此時當前呼叫會鎖定互斥量並返回。

與pthread_mutex_lock()類似的函式還有pthread_mutex_trylock()和pthread_mutex_timedlock()。

#include int pthread_mutex_trylock(pthread_mutex_t *mutex);
#include #include int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout);
這兩個函式是pthreads api中基於pthread_mutex_lock()函式的兩個變體,與pthread_mutex_lock()用法基本相同,不同之處在於:

pthread_mutex_trylock()不會阻塞當前執行緒,呼叫後直接返回乙個值來描述互斥鎖的狀態:

0:成功獲取到鎖;

ebusy:互斥量已經被鎖定,返回ebusy;

eubval:互斥量未被初始化;

eagain:互斥量的lock count已經超過遞迴鎖的最大值,無法再獲取該互斥量。

pthread_mutex_timedlock()指定了乙個附加引數abs_timeout,用於設定等待獲取互斥量時的休眠時間限制。如果abs_timeout指定的時間間隔超時,而呼叫執行緒又沒有獲得對互斥量的所有權,那麼pthread_mutex_timedlock()返回etimedout錯誤。

pthread_mutex_trylock()與pthread_mutex_timedlock()在實際使用中頻率較低,不多贅述。

#include #include #include #include #include static int cnt = 0;

static pthread_mutex_t mutex = pthread_mutex_initializer;

struct timeval t_start, t_end;

time_t time_intval;

void *func1(void *arg)

gettimeofday(&t_end, null);

time_intval = (t_end.tv_sec * 1000000 + t_end.tv_usec) - (t_start.tv_sec * 1000000 + t_start.tv_usec);

printf("time without mutex: %ld \n", time_intval);

return null;

}void *func2(void *arg)

return null;

}int main()

ret = pthread_create(&mythread_2, null, func2, null);

if(ret != 0)

ret = pthread_join(mythread_1, null);

if(ret != 0)

ret = pthread_join(mythread_2, null);

if(ret != 0)

printf("the final number is: %d \n", cnt);

return 0;

}

在使用pthread_mutex_lock()與pthread_mutex_unlock()時,耗時如下:

在以上程式示例中,去掉對pthread_mutex_lock()與pthread_mutex_unlock()的使用,執行結果如下:

不加鎖的情況下,乙個執行緒執行所需要的時間約為2.765ms,但計算出了錯誤的結果;加鎖的執行時間約為24.006ms,耗時增加了乙個數量級。但在通常情況下,執行緒會花費更多時間去處理非臨界區,對臨界區的訪問只佔少量時間,對互斥量的操作也相對較少,因此,使用互斥量對大部分應用程式的效能並無顯著影響,並且,相對於給出錯誤的結果,加鎖所付出的這點效能代價仍然是應用程式開發者可以接受的。

Linux執行緒同步之互斥量(mutex)

互斥量 也稱為互斥鎖 出自posix 執行緒標準,可以用來同步同一程序中的各個執行緒。當然如果乙個互斥量存放在多個程序共享的某個記憶體區中,那麼還可以通過互斥量來進行程序間的同步。互斥量,從字面上就可以知道是相互排斥的意思,它是最基本的同步工具,用於保護臨界區 共享資源 以保證在任何時刻只有乙個執行...

多執行緒 同步 Mutex互斥量

建立互斥量 handle createmutex lpsecurity attributes lpmutexattributes,安全性 bool binitialowner,true 建立執行緒擁有互斥量,false 相反 lpctstr lpname 執行緒名字,如果為null表示匿名,否則為命...

Linux執行緒同步 互斥量 mutex

互斥量從本質上說就是一把鎖,提供對共享資源的保護訪問.1.初始化 在linux下,執行緒的互斥量資料型別是pthread mutex t.在使用前,要對它進行初始化 對於靜態分配的互斥量,可以把它設定為pthread mutex initializer,或者呼叫pthread mutex init....