APUE之執行緒(四)

2021-07-10 18:35:03 字數 3207 閱讀 4649

執行緒同步:

執行緒同步問題,可以說是每一本經典的作業系統教程都能會提到。簡單的說就是對於乙個變數,如果乙個程序可以修改,其他的程序也可以讀取或者修改這個變數的時候,就需要對這些程序進行同步,以確保他們在訪問變數儲存的內容的時候不會訪問到無效的資料。

互斥量:

互斥變數的資料型別用pthread_mutex_t資料型別來表示,使用前必須要初始化,可以把他設定位常量,pthread_mutex_initializer(只對靜態分配的互斥量),也可以通過呼叫pthread_mutex_init()函式來進行初始化。如果動態分配互斥量(例如通過malloc()),那麼在釋放記憶體前需要呼叫pthread_mutex_destory。

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

int pthread_mutex_destory(pthread_mutex_t *mutex);

要用預設的屬性進行初始化互斥量,只需要把attr設定為null。

對互斥量進行加鎖,需要呼叫pthread_mutex_lock,如果互斥量已經上鎖,呼叫執行緒將阻塞知道互斥量被解鎖。解鎖互斥量用pthread_mutex_unlock。

#include int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

如果執行緒不希望被阻塞,那麼他可以使用pthread_mutex_trylock()嘗試對互斥量進行加鎖。如果呼叫pthread_mutex_trylock()時互斥量處於未鎖住的狀態,那麼這個函式將鎖住互斥量,不會出現阻塞並返回0,否則pthread_mutex_trylock()就會失敗,不能鎖住互斥量,返回ebusy。

下面的**用於保護某個資料結構的互斥量。

/*

*name : list11_5.c

*author : lniper

*date : 2016-02-17

*aim : using the mutex to protect the data struct.

*/#include #include struct foo;

struct foo *foo_alloc(void)

/* ...continue initialization ... */

} return (fp);

}void foo_hold(strcut foo *fp)

void foo_rele(struct foo *fp)

else

}

以上可以看出在foo_alloc函式將引用計數初始化為1是沒有必要加鎖,因為在這個操作前分配執行緒是唯一引用該物件的執行緒。但是在這之後如果要將該物件放到乙個列表中,那麼他就有可能被別的執行緒發現,因此需要首先對他加鎖。

總結一下,執行緒在使用物件前需要對物件的引用計數加1,當物件使用完畢,需要對引用計數減1。當最後乙個引用被釋放的時候,物件所占用的記憶體空間就被釋放了。

避免死鎖:

如果執行緒對同乙個互斥量加鎖兩次,那麼自身就會陷入死鎖狀態。比如說,程式中使用多個互斥量時,如果允許乙個執行緒一直占用第乙個互斥量,並且在試圖鎖住第二個互斥量的時候處於阻塞的狀態,但是擁有第二個互斥量的執行緒試圖鎖住第乙個互斥量的時候,這個時候如果沒有「外力」的介入打破這種僵局就會產生死鎖。

下面這個例子用以描述互斥量的使用方法,當同時需要兩個互斥量的時候,總是讓他們以相同的順序進行加鎖,從而來避免死鎖的發生。第二個互斥量維護者乙個用於跟蹤foo資料結構的雜湊表。這樣hashlock互斥量保護的foo結構中的fh雜湊表和f_next雜湊鏈欄位。foo結構中的f_lock互斥量保護對foo結構中的其他欄位的訪問。

/*

*name : list11_6.c

*author : lniper

*date : 2016-02-17

*aim : using double mutexs.

*/#include #include #define nhash 29

#define hash(fp) (((unsigned long)fp)%nhash)

struct foo *fh[nhash];

pthread_mutex_t hashlock = pthread_mutex_initializer;

struct foo;

struct foo *foo_alloc(void)

idx= hash(fp);

pthread_mutex_lock(&hashlock);

fp->f_next = fh[idx];

fh[idx] = fp;

pthread_mutex_lock(&fp->f_lock);

pthread_mutex_unlock(&hashlock);

/* ...continue initialization ... */

pthread_mutex_unlock(&fp->f_lock);

} return (fp);

}void foo_hold(strcut foo *fp)

struct foo *foo_find(int id)

} pthread_mutex_unlock(&hashlock);

return (fp);

}void foo_rele(struct foo *fp)

/* remove from list */

idx = hash(fp);

tfp = fh[idx];

if(tfp == fp)

else

pthread_mutex_unlock(&hashlock);

pthread_mutex_unlock(&fp->f_lock);

pthread_mutex_destroy(&fp->f_lock);

free(fp);

} else

}

這裡維護兩個互斥量,乙個是全域性互斥量hashlock,乙個是結構體內部的互斥量f_lock,全域性互斥量是hash表自身的互斥量,每次先加鎖全域性,在加鎖區域性的互斥量從而來避免死鎖的發生。

APUE之執行緒初探

執行緒 什麼是執行緒?很多介紹都是 輕量級的程序 不過感覺執行緒的定義一直都比較模糊,沒有找到什麼具體的定義。倒是覺得 程序是資源分配的最小單位,執行緒是排程的基本單位 這個說法算是比較認可的。現在主要探索的就是apue中提供的關於執行緒的相關函式。執行緒標示 和程序一樣,執行緒也有自己的id,li...

APUE之執行緒(五)

執行緒同步 讀寫鎖 繼續往下說執行緒同步問題。讀寫鎖與互斥量類似,但是讀寫鎖的好處是允許更高的並行性。讀寫鎖有三種狀態 讀模式下加鎖狀態,寫模式下加鎖狀態,不加鎖狀態。下面有中情況需要說明以下,寫加鎖狀態時,未被解鎖的時候,所有試圖對這個鎖進行加鎖的執行緒都會被阻塞。讀加鎖狀態時,所有以讀模式對它進...

APUE學習筆記 執行緒

採用多執行緒模式可以採用同步程式設計,而非非同步程式設計,可以簡化程式設計 多個程序間可以很方便的共享資料 可以通過pthread self獲得自身的執行緒id。執行緒id只在程序內部唯一。新建立執行緒不能保證那個執行緒先執行,新縣城可以訪問程序的位址空間,繼承執行緒的浮點環境和訊號遮蔽字。如果任意...