Linux多執行緒臨界區問題

2021-08-15 01:30:09 字數 4154 閱讀 6545

臨界區指的是乙個訪問共用資源(例如:共用裝置或是共用儲存器)的程式片段,而這些共用資源又無法同時被多個執行緒訪問的特性。當有執行緒進入臨界區段時,其他執行緒或是程序必須等待,有一些同步的機制必須在臨界區段的進入點與離開點實現,以確保這些共用資源是被互斥獲得使用,例如:semaphore。只能被單一執行緒訪問的裝置,例如:印表機。

看下面乙個例子,

#include#include#include#include#define num_thread 100

void *thread_inc(void *arg);

void *thread_des(void *arg);

long long num=0;

int main()

void *thread_des(void *arg)

--2個執行緒同時執行

thread_inc函式

--2個執行緒同時執行

thread_des函式

--2個執行緒同時分別執行

thread_inc函式和

thread_des函式

執行緒同步

執行緒同步用於解決執行緒訪問順序引發的問題,需要同步的情況可以從如下兩方面考慮

1、同時訪問同一記憶體空間時發生的情況

2、需要指定訪問同一記憶體空間的執行緒執行順序的情況

控制線程執行順序是指:假設有a、b兩個執行緒,執行緒a負責向指定記憶體空間寫入資料,執行緒b負責取走該資料。這種情況下,執行緒a首先應該訪問約定的記憶體空間並儲存資料。萬一執行緒b先訪問並取走資料,將導致錯誤結果。像這種需要控制執行順序的情況也需要使用同步技術。

互斥量互斥量即mutual exclusion,表示不允許多個執行緒同時訪問。互斥量主要用於解決執行緒同步訪問的問題。執行緒中為了保護理解區需要引入鎖機制,互斥量就是一把鎖,下面是互斥量的建立及銷毀函式

#includeint pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

//成功時返回0,失敗時返回其他值

mutex---建立互斥量時傳遞儲存互斥量的變數位址值,銷毀時傳遞需要銷毀的互斥量位址值

attr---傳遞時將建立的互斥量屬性,沒有特別需要指定的屬性時傳遞null

從上述函式宣告中也可以看出,為了建立相當於鎖系統的互斥量,需要宣告如下pthread_mutex_t mutex;

該變數的位址將傳遞給pthead_mutex_init函式,用來儲存作業系統建立的互斥量。呼叫pthread_mutex_destroy函式時同樣需要該資訊。

下面是利用互斥量鎖住或釋放臨界區時使用的函式

#includeint pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

//成功時返回0,失敗時返回其他值

進入臨界區前呼叫的函式就是

pthread_mutex_lock。呼叫該函式時,發現有其他程序已進入臨界區,則

pthread_mutex_lock函式不會返回,直到裡面的執行緒呼叫

pthread_mutex_unlcok函式退出臨界區為止。也就是說,其他執行緒讓出臨界區之前,當前執行緒將一直處於阻塞狀態。下面是保護臨界區的**塊編寫方法

pthread_mutex_lock(&mutex);

//臨界區的開始

//......

//臨界區的結束

pthread_mutex_unlock(&mutex);

需要注意的是,執行緒退出臨界區時,如果忘了呼叫

pthread_mutex_unlock函式,那麼其他為了進入臨界區而呼叫

pthread_mutex_lock函式的執行緒就無法擺脫阻塞狀態。這種情況稱為「

死鎖」,下面利用互斥量解決示例中遇到的問題

#include#include#include#include#define num_thread 100

void* thread_inc(void *arg);

void* thread_dec(void *arg);

long long num=0;

pthread_mutex_t mutex; //儲存互斥量讀取值的變數

int main()

以上臨界區劃分範圍較大,但這是考慮到---最大限度減少互斥量

lock、unlock函式的呼叫次數。

thread_des函式比thread_inc函式多呼叫49999999次互斥量lock、unlock函式。如果不太關注執行緒的等待時間,可以適當擴充套件臨界區。但變數num的值增加到50000000前不允許其他執行緒訪問,反而成了缺點。

訊號量下面所介紹的訊號量是「二進位制訊號量」(只用0和1)完成控制線程順序為中心的同步方法。下面給出訊號量建立及銷毀方法。

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

int sem_destroy(sem_t *sem);

//成功時返回0,失敗時返回其他值

sem---建立訊號量時傳遞儲存訊號量的變數位址值,銷毀時傳遞需要銷毀的訊號量變數位址值

pshared---傳遞其他值時,建立由多個程序共享的訊號量;傳遞0時,建立只允許1個程序內部使用的訊號量。

value---指定新建立的訊號量初始值

#includeint sem_post(sem_t *sem);

int sem_wait(sem_t *sem);

//成功時返回0,失敗時返回其他值

sem---傳遞儲存訊號量讀取值的變數位址值,傳遞給

sem_post時訊號量增1,傳遞給

sem_wait時訊號量減1

呼叫sem_init函式時,作業系統將建立訊號量物件,此物件中記錄著「訊號量值」整數。該值在呼叫

sem_post函式時增1,呼叫

sem_wait函式時減1。但訊號量的值不能小於0,因此在訊號量為0的情況下呼叫

sem_wait函式時,呼叫函式的執行緒將進入阻塞狀態(因為函式未返回)。當然,此時如果有其他執行緒呼叫

sem_post函式,訊號量的值將變為1,而原本阻塞的執行緒可以通過將該訊號量重新減為0並跳出阻塞狀態。實際上通過這種特性完成臨界區的同步操作,可以通過如下形式同步臨界區(假設訊號量的初始值為1)。

sem_wait(&sem); //訊號量變為0...

//臨界區的開始

//......

//臨界區的結束

sem_post(&sem); //訊號量變為1...

呼叫

sem_wait函式進入臨界區的執行緒在呼叫

sem_post函式前不允許其他執行緒進入臨界區。訊號量的值在0和1之間跳轉,因此,具有這種機制稱為二進位制訊號量。下面給出訊號量相關示例,此是關於控制訪問順序的同步,即與如下場景類似:

執行緒a從使用者輸入得到值後存入全域性變數num,此時執行緒b將取走該值並累加。該過程共進行5次,完成後輸出總和並退出程式。

按照執行緒a、執行緒b的順序訪問變數num,且需要執行緒同步,下面是示例:

#include#include#includevoid *read(void *arg);

void *accu(void *arg);

static sem_t sem1; //生成的訊號量1

static sem_t sem2; //生成的訊號量2

static int num;

int main()

void *read(void *arg)

return null;

}void *accu(void *arg)

printf("result:%d \n",sum);

return null;

}

多執行緒程式設計 臨界區

1 windows api建立執行緒 include 包含相應標頭檔案 include dword winapi myfun1 lpvoid lpparameter 宣告執行緒函式 dword winapi myfun2 lpvoid lpparameter int main 主函式 else 如果...

windows多執行緒同步 臨界區

推薦參考部落格 秒殺多執行緒第五篇 經典執行緒同步 關鍵段cs 關於臨界區的觀念,一般作業系統書上面都有。適用範圍 它只能同步乙個程序中的執行緒,不能跨程序同步。一般用它來做單個程序內的 快同步,效率比較高 windows中與臨界區有關的結構是 critical section,關於該結構體的內部結...

多執行緒程式的臨界區

所謂的臨界區 是指程序中的一段需要訪問共享資源並且當另乙個程序處於相應 區域時便不會被執行的 區域 對於臨界區的管理的必須要滿足一下的四個要求 互斥 同一時間臨界區中最多存在乙個執行緒 progress 如是乙個執行緒想要進入臨界區,那麼它最終會成功 有限等待 如果乙個執行緒i處於入口區,那麼在i的...