1. 程式人生 > >互斥鎖 pthread_mutex_init()函數

互斥鎖 pthread_mutex_init()函數

attr 函數 有效 線程同步 2.3 printf 同時 stdlib.h 順序鎖

Linux下為了多線程同步,通常用到鎖的概念。
posix下抽象了一個鎖類型的結構:ptread_mutex_t。通過對該結構的操作,來判斷資源是否可以訪問。顧名思義,加鎖(lock)後,別人就無法打開,只有當鎖沒有關閉(unlock)的時候才能訪問資源。

即對象互斥鎖的概念,來保證共享數據操作的完整性。每個對象都對應於一個可稱為" 互斥鎖" 的標記,這個標記用來保證在任一時刻,只能有一個線程訪問該對象。

使用互斥鎖(互斥)可以使線程按順序執行。通常,互斥鎖通過確保一次只有一個線程執行代碼的臨界段來同步多個線程。互斥鎖還可以保護單線程代碼。

  要更改缺省的互斥鎖屬性,可以對屬性對象進行聲明和初始化。通常,互斥鎖屬性會設置在應用程序開頭的某個位置,以便可以快速查找和輕松修改。

1.函數原型:

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);

該函數用於C函數的多線程編程中,互斥鎖的初始化。

  pthread_mutex_init()函數是以動態方式創建互斥鎖的,參數attr指定了新建互斥鎖的屬性。如果參數attr為NULL,則使用默認的互斥鎖屬性,默認屬性為快速互斥鎖 。互斥鎖的屬性在創建鎖的時候指定,在LinuxThreads實現中僅有一個鎖類型屬性,不同的鎖類型在試圖對一個已經被鎖定的互斥鎖加鎖時表現不同。

  pthread_mutexattr_init()函數成功完成之後會返回零,其他任何返回值都表示出現了錯誤。

  函數成功執行後,互斥鎖被初始化為鎖住態。

2. 互斥鎖屬性

互斥鎖的屬性在創建鎖的時候指定,在LinuxThreads實現中僅有一個鎖類型屬性,不同的鎖類型在試圖對一個已經被鎖定的互斥鎖加鎖時表現不同。當前(glibc2.2.3,linuxthreads0.9)有四個值可供選擇:

  * PTHREAD_MUTEX_TIMED_NP,這是缺省值,也就是普通鎖。當一個線程加鎖以後,其余請求鎖的線程將形成一個等待隊列,並在解鎖後按優先級獲得鎖。這種鎖策略保證了資源分配的公平性。

  * PTHREAD_MUTEX_RECURSIVE_NP,嵌套鎖,允許同一個線程對同一個鎖成功獲得多次,並通過多次unlock解鎖。如果是不同線程請求,則在加鎖線程解鎖時重新競爭。

  * PTHREAD_MUTEX_ERRORCHECK_NP,檢錯鎖,如果同一個線程請求同一個鎖,則返回EDEADLK,否則與PTHREAD_MUTEX_TIMED_NP類型動作相同。這樣就保證當不允許多次加鎖時不會出現最簡單情況下的死鎖。

  * PTHREAD_MUTEX_ADAPTIVE_NP,適應鎖,動作最簡單的鎖類型,僅等待解鎖後重新競爭。

3. 其他鎖操作

  鎖操作主要包括加鎖pthread_mutex_lock()、解鎖pthread_mutex_unlock()和測試加鎖 pthread_mutex_trylock()三個,不論哪種類型的鎖,都不可能被兩個不同的線程同時得到,而必須等待解鎖。對於普通鎖和適應鎖類型,解鎖者可以是同進程內任何線程;而檢錯鎖則必須由加鎖者解鎖才有效,否則返回EPERM;對於嵌套鎖,文檔和實現要求必須由加鎖者解鎖,但實驗結果表明並沒有這種限制,這個不同目前還沒有得到解釋。在同一進程中的線程,如果加鎖後沒有解鎖,則任何其他線程都無法再獲得鎖。

int pthread_mutex_lock(pthread_mutex_t *mutex)

  int pthread_mutex_unlock(pthread_mutex_t *mutex)

  int pthread_mutex_trylock(pthread_mutex_t *mutex)

  pthread_mutex_trylock()語義與pthread_mutex_lock()類似,不同的是在鎖已經被占據時返回EBUSY而不是掛起等待。

4. 死鎖:

  死鎖主要發生在有多個依賴鎖存在時, 會在一個線程試圖以與另一個線程相反順序鎖住互斥量時發生. 如何避免死鎖是使用互斥量應該格外註意的東西。

  總體來講, 有幾個不成文的基本原則:

  對共享資源操作前一定要獲得鎖。

  完成操作以後一定要釋放鎖。

  盡量短時間地占用鎖。

  如果有多鎖, 如獲得順序是ABC連環扣, 釋放順序也應該是ABC。

  線程錯誤返回時應該釋放它所獲得的鎖。

下面是一段測試代碼,創建兩個線程,分別訪問全局變量gnum,並且修改它,打印出來

/*mutex.c*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
/*全局變量*/
int gnum = 0;
/*互斥量 */
pthread_mutex_t mutex;
/*聲明線程運行服務程序*/
static void pthread_func_1 (void);
static void pthread_func_2 (void);

int main (void)
{
/*線程的標識符*/
pthread_t pt_1 = 0;
pthread_t pt_2 = 0;
int ret = 0;
/*互斥初始化*/
pthread_mutex_init (&mutex, NULL);
/*分別創建線程1、2*/
ret = pthread_create( &pt_1, //線程標識符指針
NULL, //默認屬性
(void *)pthread_func_1,//運行函數
NULL); //無參數
if (ret != 0)
{
perror ("pthread_1_create");
}

ret = pthread_create( &pt_2, //線程標識符指針
NULL, //默認屬性
(void *)pthread_func_2, //運行函數
NULL); //無參數
if (ret != 0)
{
perror ("pthread_2_create");
}
/*等待線程1、2的結束*/
pthread_join (pt_1, NULL);
pthread_join (pt_2, NULL);

printf ("main programme exit!/n");
return 0;
}
/*線程1的服務程序*/
static void pthread_func_1 (void)
{
int i = 0;

for( i=0; i<3; i++ ){
printf ("This is pthread_1!/n");
pthread_mutex_lock(&mutex); /*獲取互斥鎖*/
/*註意,這裏以防線程的搶占,以造成一個線程在另一個線程sleep時多次訪問互斥資源,所以sleep要在得到互斥鎖後調用*/
sleep (1);
/*臨界資源*/
gnum++;
printf ("Thread_1 add one to num:%d/n",gnum);
pthread_mutex_unlock(&mutex); /*釋放互斥鎖*/
}

pthread_exit ( NULL );
}
/*線程2的服務程序*/
static void pthread_func_2 (void)
{
int i = 0;

for( i=0; i<5; i++ ) {
printf ("This is pthread_2!/n");
pthread_mutex_lock(&mutex); /*獲取互斥鎖*/
/*註意,這裏以防線程的搶占,以造成一個線程在另一個線程sleep時多次訪問互斥資源,所以sleep要在得到互斥鎖後調用*/
sleep (1);
/*臨界資源*/
gnum++;
printf ("Thread_2 add one to num:%d/n",gnum);
pthread_mutex_unlock(&mutex); /*釋放互斥鎖*/

}

pthread_exit ( NULL );
}

參考來源於網絡:

http://baike.baidu.com/view/4518300.html

http://baike.baidu.com/view/1461738.htm

http://blog.csdn.net/benny_cen/article/details/3969219

http://blog.csdn.net/xing_hao/article/details/6626223

http://hi.baidu.com/cunlin/blog/item/1f9e3f384c6bbeffb211c79c.html

http://blog.chinaunix.net/space.php?uid=20698441&do=blog&id=1891215

互斥鎖 pthread_mutex_init()函數