UNIX學習之執行緒

2021-10-23 07:35:11 字數 4994 閱讀 8297

後記本章開始學習unix執行緒的概念,首先看一看什麼是執行緒。

我們或多或少地對執行緒有一定了解。每乙個單獨的執行緒可以用來執行乙個操作,這樣我們就經常可以同時執行很多互不相干的操作。

執行緒有啥子優點?

注意,單核處理器也是可以多執行緒的。

#include

intpthread_equal

(pthread_t tid1,pthread_t tid2)

;

我們判斷乙個id是否為另乙個時,作業系統不能把pthread_t型別作為乙個整數來處理,所以我們必須引入乙個函式,就是pthread_equal函式。

執行緒通過pthread_create函式建立

int

pthread_create

(pthread_t *restrict tidp,

const pthread_attr_t * restrict attr,

void*(

*star_rtn)

(void*)

,void

*restrict arg)

解釋一下引數的意義:

執行緒可以通過以下三種方式終止:

(1)從啟動例程中返回;

(2)被同一程序中的其他執行緒取消;

(3)執行緒呼叫pthread_exit;

void

pthread_exit

(void

*rval_ptr)

;int

pthread_join

(pthread_t thread,

void

**rval_ptr)

;

pthread的互斥介面mutex互斥量可以用來保護資料,保證同一時間只有乙個執行緒訪問資料。mutex本質上也是一把鎖。

在mutex進行加鎖之後,其他所有試圖加鎖的執行緒都會被阻塞,直至當前執行緒釋放該互斥量。

互斥變數使用pthread_mutex_t資料型別。我們需要對它進行初始化操作。

#include

intpthread_mutex_init

(pthread_mutex_t *restrict mutex,

const pthread_mutexattr_t *restrict attr)

;int

pthread_mutex_destroy

(pthread_mutex_t *mutex)

;

對互斥量加鎖,需要呼叫pthread_mutex_lock,它將阻塞其他執行緒直至我們呼叫unlock解鎖。另外,我們還可以嘗試枷鎖,呼叫trylock。

int

pthread_mutex_lock

(pthread_mutex_t *mutex)

;int

pthread_mutex_trylock

(pthread_mutex_t *mutex)

;int

pthread_mutex_unlock

(pthread_mutex_t *mutex)

;

假如我們有兩個互斥量,乙個被執行緒一一直占有,另乙個被執行緒二一直占有,並且執行緒二在申請鎖住執行緒一的互斥量。

我們知道,如果執行緒一解鎖這個互斥量,執行緒二立馬就會對這個互斥量枷鎖。這是很正常的情況。但是,如果此時執行緒一也在申請鎖住執行緒二的互斥量,因為執行緒二此時是阻塞的(在等待互斥量一的解鎖),所以它永遠不可能解鎖,因此執行緒一不會鎖住執行緒二的互斥量,從而執行緒一也不會解鎖。。

於是,死鎖就形成了。

#include

#include

#define nhash 29

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

struct foo *

fh(nhash)

;//乙個用於跟蹤foo資料結構的雜湊表

pthread_mutex_t hashlock = pthread_mutex_initializer;

struct foo

struct foo *

foo_alloc

(int id)

idx =

hash

(id)

;//hash函式對映

pthread_mutex_lock

(&hashlock)

;//給hashlock加鎖,禁止其他執行緒修改hash表

fp->f_next = fh[idx]

;//f_next指標指向fh[idx],也就是說把新節點掛在原來的上面

fh[idx]

= fp;

//新節點作表頭

pthread_mutex_lock

(&fp->f_lock)

;//給f_lock加鎖,阻止其他執行緒訪問新結構

pthread_mutex_unlock

(&hashlock)

;//hashlock解鎖

pthread_mutex_unlock

(&fp->f_lock)

;//flock解鎖

}return

(fp);}

void

foo_hold

(struct foo *fp)

struct foo *

foo_find

(int id)

}pthread_mutex_unlock

(&hashlock)

;return

(fp);}

void

f_rele

(struct foo *fp)

idx =

hash

(fp->id)

; 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

鎖的粒度對程式效能有重要影響,鎖的粒度太粗,可能會有很多執行緒等待同乙個鎖,從而使併發性得不到有效改善。而粒度太細又會導致鎖使用的開銷太大。可以看這篇文章的比喻:鎖的粒度。

這個函式和pthread_mutex_lock功能差不多,不同的是增加了等待時間。

int

pthread_mutex_timedlock

(pthread_mutex_t *restrict mutex,

const

struct timespec *restrict tsptr)

;

讀寫鎖比互斥量更為靈活。當讀寫鎖處於寫狀態時,它和互斥量一樣,但是處於讀狀態時,它允許其他的執行緒以讀模式加鎖。因此它很適合讀遠大於寫的情況。

int

pthread_rwlock_init

(pthread_rwlock_t *restrict rwlock,

const pthread_rwlockattr_t *restrict attr)

;int

pthread_rwlock_destroy

(pthread_rwlock_t rwlock)

;

條件變數是執行緒的另外一種同步機制,這些同步物件為執行緒提供了會合的場所,理解起來就是兩個(或者多個)執行緒需要碰頭(或者說進行互動-乙個執行緒給另外的乙個或者多個執行緒傳送訊息),我們指定在條件變數這個地方發生,乙個執行緒用於修改這個變數使其滿足其它執行緒繼續往下執行的條件,其它執行緒則接收條件已經發生改變的訊號。

這篇部落格寫得很好,舉了乙個訊息佇列的例子:新增鏈結描述。

我們同樣可以用兩種方式初始化條件變數。第一種是用常量pthread_cond_initializer分配給靜態的條件變數。另一種是使用int pthread_conda_init函式。

int

pthread_cond_init

(pthread_cond_t *restrict cond,

const pthread_condattr_t *restrict attr)

;int

pthread_cond_destroy

(pthread_cond_t *cond)

;

pthread_cond_wait函式對傳遞給它的互斥量進行保護。當wait函式被呼叫以後,它會將呼叫此函式的執行緒放到等待條件的執行緒列表上,並對互斥量解鎖。在上文的例子中:

while

(workq ==

null

)pthread_cond_wait

(&qready,

&qlock)

;

為什麼要對這個互斥量解鎖?因為此時,其他執行緒就可以改變qready了。如果函式返回,那麼它就再次被鎖住。

那麼,在生產者中,我們也需要呼叫乙個函式發訊號:

pthread_cond_signal

(&qready)

;

執行緒加鎖互斥量時,如果互斥量處於加鎖,則執行緒會被掛起。掛起和喚醒直接,存在核心的消耗。另一類鎖被稱為自旋鎖,顧名思義,它在加鎖不成功時會迴圈檢測鎖是否unlock,這樣做的壞處是迴圈檢測時cpu不能做其他事情,因此它適用於鎖持有時間較短的場合。

屏障允許每個執行緒等待,直到所有的合作執行緒都到達某一點,然後從該點繼續執行。

初始化使用pthread_barrier_init函式。使用pthread_barrier_wait函式等待程序進入屏障,如果最後乙個wait函式返回,那麼滿足了屏障計數,所有的執行緒都被喚醒了。

這一章概念比較多,加上心情不太好,看了三天才看完。即使看完了也並不能說掌握了吧,還是要找機會程式設計實踐才行。

Unix 多執行緒

unix 執行緒 先來介紹執行緒的最基本操作 由淺入深 執行緒建立 pthread t threadid 執行緒的id儲存型別 型別為unsuigned long int int pthread create pthread t,執行緒的唯一標識id const pthread attr t 優先順...

Unix執行緒同步

執行緒屬性 pthread介面允許我們通過設定每個物件關聯的不同屬性來細調執行緒和同步物件的行為。通常,管理這些屬性的函式都遵循相同的模式。每個物件與他自己的型別的屬性物件進行關聯,執行緒與執行緒屬性關聯,互斥量與互斥量屬性關聯。有乙個初始化函式,把屬性設為預設值。銷毀屬性物件的函式,如果初始化函式...

unix執行緒控制

include int pthread pthread t restrict tipd,const pthread attr t restrict attr,void start rtn void void restrict arg 返回值 若成功返回0 否則,返回錯誤編號fork 子執行緒複製父執...