Linux下執行緒同步的幾種常見方法

2021-08-20 14:05:12 字數 4819 閱讀 9589

linux下提供了多種方式來處理執行緒同步,最常用的是互斥鎖、條件變數和訊號量。

一、互斥鎖(mutex)

鎖機制是同一時刻只允許乙個執行緒執行乙個關鍵部分的**。

1. 初始化鎖

int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);

其中引數 mutexattr 用於指定鎖的屬性(見下),如果為null則使用預設屬性。

互斥鎖的屬性在建立鎖的時候指定,在linuxthreads實現中僅有乙個鎖型別屬性,不同的鎖型別在試圖對乙個已經被鎖定的互斥鎖加鎖時表現不同。當前有四個值可供選擇:

(1)pthread_mutex_timed_np,這是預設值,也就是普通鎖。當乙個執行緒加鎖以後,其餘請求鎖的執行緒將形成乙個等待佇列,並在解鎖後按優先順序獲得鎖。這種鎖策略保證了資源分配的公平性。

(2)pthread_mutex_recursive_np,巢狀鎖,允許同乙個執行緒對同乙個鎖成功獲得多次,並通過多次unlock解鎖。如果是不同執行緒請求,則在加鎖執行緒解鎖時重新競爭。

(3)pthread_mutex_errorcheck_np,檢錯鎖,如果同乙個執行緒請求同乙個鎖,則返回edeadlk,否則與pthread_mutex_timed_np型別動作相同。這樣就保證當不允許多次加鎖時不會出現最簡單情況下的死鎖。

(4)pthread_mutex_adaptive_np,適應鎖,動作最簡單的鎖型別,僅等待解鎖後重新競爭。

2. 阻塞加鎖

int pthread_mutex_lock(pthread_mutex *mutex);

3. 非阻塞加鎖

int pthread_mutex_trylock( pthread_mutex_t *mutex);

該函式語義與 pthread_mutex_lock() 類似,不同的是在鎖已經被佔據時返回 ebusy 而不是掛起等待。

4. 解鎖(要求鎖是lock狀態,並且由加鎖執行緒解鎖)

int pthread_mutex_unlock(pthread_mutex *mutex);

5. 銷毀鎖(此時鎖必需unlock狀態,否則返回ebusy)

int pthread_mutex_destroy(pthread_mutex *mutex);

示例**:

[oracle@localhost]$ cat mutextest.c

#include

#include

#include

#include

pthread_mutex_t mutex = pthread_mutex_initializer;

int gn;

void* thread(void *arg)

int main()

else

pthread_join(id, null);

pthread_mutex_destroy(&mutex);

return 0;

}示例**1:

[oracle@localhost]$ cat condtest1.c

[oracle@localhost]$ 

示例**2:

[oracle@localhost]$ cat condtest2.c

#include

#include

#include "stdio.h"

#include "stdlib.h"

static pthread_mutex_t mtx = pthread_mutex_initializer;

static pthread_cond_t cond = pthread_cond_initializer;

struct node

*head = null;

static void cleanup_handler(void *arg)

static void *thread_func(void *arg)

pthread_mutex_unlock(&mtx); // 臨界區資料操作完畢,釋放互斥鎖。

}pthread_cleanup_pop(0);

return 0;

}int main(void)

printf("thread 1 wanna end the line.so cancel thread 2.\n");

/* 關於pthread_cancel,有一點額外的說明,它是從外部終止子執行緒,子執行緒會在最近的取消點,

* 退出執行緒,而在我們的**裡,最近的取消點肯定就是pthread_cond_wait()了。*/

pthread_cancel(tid);

pthread_join(tid, null);

printf("all done -- exiting\n");

return 0;

}[oracle@localhost]$ 

可以看出,等待條件變數訊號的用法約定一般是這樣的:

...pthread_mutex_lock(&mutex);

...pthread_cond_wait (&cond, &mutex);

...pthread_mutex_unlock (&mutex);

...相信很多人都會有這個疑問:為什麼pthread_cond_wait需要的互斥鎖不在函式內部定義,而要使使用者定義的呢?現在沒有時間研究 pthread_cond_wait 的源**,帶著這個問題對條件變數的用法做如下猜測,希望明白真相看過源**的朋友不吝指正。

1. pthread_cond_wait 和 pthread_cond_timewait 函式為什麼需要互斥鎖?因為:條件變數是執行緒同步的一種方法,這兩個函式又是等待訊號的函式,函式內部一定有須要同步保護的資料。

2. 使用使用者定義的互斥鎖而不在函式內部定義的原因是:無法確定會有多少使用者使用條件變數,所以每個互斥鎖都須要動態定義,而且管理大量互斥鎖的開銷太大,使用使用者定義的即靈活又方便,符合unix哲學的程式設計風格(隨便推薦閱讀《unix程式設計哲學》這本好書!)。

3. 好了,說完了1和2,我們來自由猜測一下 pthread_cond_wait 函式的內部結構吧:

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)

...}

三、 訊號量

如同程序一樣,執行緒也可以通過訊號量來實現通訊,雖然是輕量級的。

執行緒使用的基本訊號量函式有四個:

#include

1. 初始化訊號量

int sem_init (sem_t *sem , int pshared, unsigned int value);

引數:sem - 指定要初始化的訊號量;

pshared - 訊號量 sem 的共享選項,linux只支援0,表示它是當前程序的區域性訊號量;

value - 訊號量 sem 的初始值。

2. 訊號量值加1

給引數sem指定的訊號量值加1。

int sem_post(sem_t *sem);

3. 訊號量值減1

給引數sem指定的訊號量值減1。

int sem_wait(sem_t *sem);

如果sem所指的訊號量的數值為0,函式將會等待直到有其它執行緒使它不再是0為止。

4. 銷毀訊號量

銷毀指定的訊號量。

int sem_destroy(sem_t *sem);

示例**:

[oracle@localhost]$ cat semtest.c

#include

#include

#include

#include

#include

#include

#define return_if_fail(p) if((p) == 0)

typedef struct _privinfo

privinfo;

static void info_init (privinfo* prifo);

static void info_destroy (privinfo* prifo);

static void* pthread_func_1 (privinfo* prifo);

static void* pthread_func_2 (privinfo* prifo);

int main (int argc, char** argv)

info_init (prifo);

ret = pthread_create (&pt_1, null, (void*)pthread_func_1, prifo);

if (ret != 0)

ret = pthread_create (&pt_2, null, (void*)pthread_func_2, prifo);

if (ret != 0)

pthread_join (pt_1, null);

pthread_join (pt_2, null);

info_destroy (prifo);

return 0;

}static void info_init (privinfo* prifo)

static void info_destroy (privinfo* prifo)

static void* pthread_func_1 (privinfo* prifo)

return;

}static void* pthread_func_2 (privinfo* prifo)

return;

}[oracle@localhost]$ 

也可參考:

posix執行緒程式設計指南(3)

linux執行緒同步之條件變數

linux下執行緒同步之互斥鎖

互斥鎖是多執行緒同步的一種方式,當多個執行緒訪問同乙個變數時,最簡單的方法就是使用乙個互斥鎖 mutex 保護這個共享變數,防止出現資源搶占的問題。下面是未加互斥鎖時 include includepthread mutex t mutex pthread mutex initializer 靜態初...

linux下執行緒同步之條件變數

以下是生產者消費者 實現 a執行緒生產產品到共享陣列,b執行緒從中消費。include include include pthread mutex t mutex pthread mutex initializer 並且初始化鎖 pthread cond t cond pthread cond in...

Linux下執行緒

此文講述的執行緒為linux下,其執行緒庫函式是由posix標準定義的,稱為posix thread或者pthread。在linux上線程函式位於libpthread共享庫中,因此在編譯時要加上 lpthread選項。建立執行緒 終止執行緒 等待執行緒 三個函式都為pthread.h中定義,其中要注...