Linux下C的線程同步機制


C里提供了保證線程安全性的三種方法:

(添加頭文件#include<pthread.h>,pthread 庫不是 Linux 系統默認的庫,連接時需要使用靜態庫 libpthread.a, 在編譯中要加 -lpthread參數)

  • 互斥鎖

  通過鎖的機制實現線程間的互斥,同一時刻只有一個線程可以鎖定它,當一個鎖被某個線程鎖定的時候,如果有另外一個線程嘗試鎖定這個臨界區(互斥體),則第二個線程會被阻塞,或者說被置於等待狀態。只有當第一個線程釋放了對臨界區的鎖定,第二個線程才能從阻塞狀態恢復運行。

  int pthread_mutex_init(pthread_mutex_t* mutex, const thread_mutexattr_t* mutexattr);初始化一個互斥鎖。

  int pthread_mutex_lock(pthread_mutex_t* mutex);如果mutex被鎖定,當前進程處於等待狀態;否則,本進程獲得互斥鎖並進入臨界區。

  int pthread_mutex_trylock(pthread_mutex_t* mutex);和lock不同的時候,嘗試獲得互斥鎖不成功不會使得進程進入阻塞狀態,而是繼續返回線程執行。該函數可以有效避免循環等待鎖,如果trylock失敗可以釋放已經占有的資源,這樣可以避免死鎖

  int pthread_mutex_unlock(pthread_mutex_t* mutex);釋放互斥鎖,並使得被阻塞的線程獲得互斥鎖並執行。

  int pthread_mutex_destroy(pthread_mutex_t* mutex);用來撤銷互斥鎖的資源。

pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);


void pthread1(void* arg){
   pthread_mutex_lock(&mutex);
   .....//臨界區
   pthread_mutex_unlock(&mutex);
}


void pthread2(void* arg){
   pthread_mutex_lock(&mutex);
   .....//臨界區
   pthread_mutex_unlock(&mutex);
}
  • 讀寫鎖

讀寫鎖與互斥量類似,不過讀寫鎖允許更高的並行性。適用於讀的次數大於寫的次數的數據結構。

一次只有一個線程可以占有寫模式的讀寫鎖,但是多個線程可以同時占有讀模式的讀寫鎖。

讀鎖鎖住,加讀鎖,可以;加寫鎖會被阻塞,但此時會阻塞后續的讀鎖請求,防止讀鎖長期占用無法進入寫模式。寫鎖就是互斥鎖。

int pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr);初始化讀寫鎖

int pthread_destroy(pthread_rwlock_t* rwlock);銷毀讀寫鎖

int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);加讀鎖

int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);加寫鎖

int pthread_rwlock_unlock(pthread_rwlock_t* rwlock);解鎖

  • 條件變量

  信號量只有鎖住和不鎖兩種狀態,而且當條件變量和信號量一起使用時,允許線程以無競爭的方式等待特定的條件發生

  條件本身是由互斥量保護的:線程在改變條件狀態之前必須先鎖住互斥量。

  int pthread_cond_init(pthread_cond_t* cond,const pthread_condattr_t* attr);初始化動態分配的條件變量;也可以直接用PTHREAD_INITIALIZER直接賦值給靜態的條件變量

  int pthread_cond_destroy(pthread_cond_t* cond)撤銷條件變量資源;

  int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);使用該函數使得等待條件變量為真。線程被條件變量cond阻塞。

  int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex,const struct timespec* tspr);與wait類似,只是經歷tspr時間后,即使條件變量不滿足,阻塞也被解除,返回錯誤碼。

  int pthread_cond_signal(pthread_cond_t* cond);喚醒因為條件變量阻塞的線程。

  int pthread_cond_broadcast(pthread_cond_t* cond);喚醒等待該條件的所有線程。

  

pthread_cond_t cond;
pthread_mutex_t mutex;
int count=0;
void pthread1(void* arg){
    pthread_mutex_lock(&mutex);
    while(count==0)
        pthread_cond_wait(&cond,&mutex);
    count--;
    pthread_mutex_unlock(&mutex);
}
void pthread2(void* arg){
    pthread_mutex_lock(&mutex);
    if(count==0)
        pthread_cond_signal(&cond);
    count++;
    pthread_mutex_unlock(&mutex);
}
  • 自旋鎖

  互斥量阻塞線程的方式是使其進入睡眠,而自旋鎖是讓線程忙等,即不會使其睡眠,而是不斷循判斷自旋鎖已經被解鎖。

  適用於占用自旋鎖時間比較短的情況。

  • 信號量

介紹一下POSIX(POSIX標准定義了操作系統應該為應用程序提供的接口標准,換句話說,為一個POSIX兼容的操作系統編寫的程序,應該可以在任何其它的POSIX操作系統(即使是來自另一個廠商)上編譯執行。)的信號量機制,定義在頭文件/usr/include/semaphore.h

1)初始化一個信號量:sem_init()

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

pshared為0時表示該信號量只能在當前進程的線程間共享,否則可以進程間共享,value給出了信號量的初始值。

2)阻塞線程

sem_wait(sem_t* sem)直到信號量sem的值大於0,解除阻塞后將sem的值減一,表明公共資源經使用后減少;sem_trywait(sem_t* sem)是wait的非阻塞版本,它直接將sem的值減一,相當於P操作。

3)增加信號量的值,喚醒線程

sem_post(sem_t* sem)會使已經被阻塞的線程其中的一個線程不再阻塞,選擇機制同樣是由線程的調度策略決定的。相當於V操作。

3)釋放信號量資源

sem_destroy(sem_t* sem)用來釋放信號量sem所占有的資源

pthread_mutex_t mutex;
sem_t full,empty;

void producer(void* arg){
    while(1){
    sem_wait(&empty);//need to produce. the the empty of resource need minus 1
    pthread_mutex_lock(&mutex);
    ...//produce a resource
    pthread_mutex_unlock(&mutex);
    sem_post(&full); //have produced a resource, the the full of resource need add 1
    }
}
void consumer(void* arg){
    while(1){
    sem_wait(&full);
    pthread_mutex_lock(&mutex);
    ...//consume a resource
    pthread_mutex_unlock(&mutex);
    sem_post(&empty); 
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM