日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

互斥锁、条件变量

發布時間:2023/11/30 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 互斥锁、条件变量 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、互斥鎖

1. 函數原型:

pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); pthread_mutex_destroy(pthread_mutex_t *mutex);

分析:

  • pthread_mutex_t 類型,其本質是一個結構體,為簡化理解,應用時可忽略其實現細節,簡單當成整數看待。
  • pthread_mutex_t??mutex:變量mutex只有兩種取值0、1;

函數一參數1:傳出參數,調用時應傳&mutex

  • restrict關鍵字:只用于限制指針,告訴編譯器,所有修改該指針指向內存中內容的操作,只能通過本指針完成。不能通過除本指針以外的其他變量或指針修改。

函數一參數2:互斥屬性。是一個傳入參數,通常傳NULL,選用默認屬性(線程間共享).

  • 靜態初始化:如果互斥鎖mutex是靜態分配的(定義在全局,或加了static關鍵字修飾),可以直接使用宏進行初始化。pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • 動態初始化:局部變量應采用動態初始化, pthread_mutex_init(&mutex, NULL);

?

pthread_mutex_lock(pthread_mutex_t *mutex); pthread_mutex_unlock(pthread_mutex_t *mutex);

分析:

  • 函數1:沒有被上鎖,當前線程會將這把鎖鎖上;被鎖上了,當前線程阻塞,鎖被打開之后,線程解除阻塞(加鎖。可理解為將mutex--(或-1))。
  • 函數2:同時將阻塞在該鎖上的所有線程全部喚醒解鎖(可理解為將mtex++(或+1)).

?

2. 測試代碼:

#include <stdio.h> #include <string.h> #include <pthread.h> #include <stdlib.h> #include <unistd.h>void *tfn(void *arg) {srand(time(NULL));while(1) {printf("hello ");sleep(rand() % 3); //模擬長時間操作共享資源,導致cpu易主,產生與時間有關的錯誤printf("word\n");sleep(rand() % 3);}return NULL; }int main() {pthread_t tid;srand(time(NULL));pthread_create(&tid, NULL, tfn, NULL);while(1) {printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");sleep(rand() % 3);}return 0; }

輸出結果:

?

??3. 測試代碼:

#include <stdio.h> #include <string.h> #include <pthread.h> #include <stdlib.h> #include <unistd.h>void *tfn(void *arg) {srand(time(NULL));while(1) {printf("hello ");sleep(rand() % 3); //模擬長時間操作共享資源,導致cpu易主,產生與時間有關的錯誤printf("word\n");sleep(rand() % 3);}return NULL; }int main() {pthread_t tid;srand(time(NULL));pthread_create(&tid, NULL, tfn, NULL);while(1) {printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");sleep(rand() % 3);}return 0; }

輸出結果

?

二、 條件變量

條件變量本身不是鎖,但它也可以造成線程阻塞,通常與互斥鎖配合使用,給多線程提供一個會合的場所。

?

1. 函數原型:

pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t * attr); //初始化一個條件變量 pthread_cond_destroy(pthread_cond_t *cond); // 銷毀一個條件變量 pthread_cond_signal(pthread_cond_t *cond); // 喚醒至少一個阻塞在條件變量上的線程 pthread_cond_broadcast(pthread_cond_t *cond); // 喚醒全部阻塞在條件變量上的線程

?

2. 函數原型:

pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

分析:

函數作用:阻塞等待一個條件變量

  • 阻塞等待條件變量cond(參數1)滿足
  • 釋放已掌握的互斥鎖(解鎖互斥量),相當于pthread_mutex_unlock(&mutex); {1、2兩步為一個原子操作}
  • 當被喚醒,pthread_cond_wait函數返回,解除阻塞并重新獲取互斥鎖pthread_mutex_lock(&mutex);
  • ?

    3. 函數原型:

    ? ??函數作用:限時等待一個條件變量

    pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);

    參數3:

    struct timespec {time_t tv_sec; seconds 秒 long tv_nsec; nanoseconds 納秒 }

    形參:abstime:絕對時間

    如:time(NULL)返回的就是絕對時間。而alarm(1)是相對時間,相當當前時間定時1秒鐘。

    struct timespec t = {1,??0};

    pthread_cond_time(&cond, &mutex, &t);只能定時到1970年1月1日00:00:01秒(早已經過去)

    正確用法:

    time_t cur = time(NULL); 獲取當前時間 struct timespec t; 定義timespec結構體變量 t.tv_sec = cur + 1; 定時一秒 pthread_cond_timewait(&cond, mutex, &t) 傳參

    ?

    4. 函數原型:

    pthread_cond_signal(pthread_cond_t *cond); // 喚醒至少一個阻塞在條件變量上的線程 pthread_cond_broadcast(pthread_cond_t *cond); // 喚醒全部阻塞在條件變量上的線程

    ?

    ?

    三、生產者消費者條件變量模型

    線程同步典型的案例即為生產者消費者模型,而借助條件變量來實現這一案例,是比較常見的方法,假定有兩個線程,一個模擬生產者行為,一個模擬消費者行為,兩個線程同時操作一個共享資源(一般稱之為匯聚),生產者向其中添加產品,消費者從中消費掉產品。

    1. 測試代碼:

    #include <pthread.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h>struct msg {struct msg *next;int num; };struct msg *head; struct msg *mp;pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; //靜態初始化:一個條件變量和一個互斥量 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;void *consumer(void *p) {for (; ;){pthread_mutex_lock(&lock);while (head == NULL) //頭指針為空,說明沒有節點 可以為if嗎 pthread_cond_wait(&has_product, &lock);mp = head;head = mp->next; //模擬消費掉一個產品pthread_mutex_unlock(&lock);printf("-consume-----%d\n", mp->num);free(mp);sleep(rand() % 5);} }void *producer(void *p) {for (; ;) {mp = malloc(sizeof(struct msg));mp->num = rand() % 1000 + 1; //模擬生產一個產品printf("-Produce----%d\n", mp->num);pthread_mutex_lock(&lock);mp->next = head;head = mp;pthread_mutex_unlock(&lock);pthread_cond_signal(&has_product); //將等待在該條件變量上的一個線程喚醒sleep(rand() % 5);} }int main() {pthread_t pid, cid;srand(time(NULL));pthread_create(&pid, NULL, producer, NULL);pthread_create(&cid, NULL, consumer, NULL);pthread_join(pid, NULL);pthread_join(cid, NULL);return 0; }

    輸出結果:

    ?【注意】:為什么用while循環而不用if呢?

    一個生產者可能對應著多個消費者,生產者向隊列中插入一條數據之后發出signal,然后各個消費者線pthread_cond_wait獲取mutex后返回,當然,這里只有一個線程獲取到了mutex,然后進行處理,其它線程會pending在這里,處理線程處理完畢之后釋放mutex,剛才等待的線程中有一個獲取mutex,如果這里用if,就會在當前隊列為空的狀態下繼續往下處理,這顯然是不合理的。

    ?

    ?

    五、參考資料

    1?深入解析條件變量(condition variables)
    ?

    總結

    以上是生活随笔為你收集整理的互斥锁、条件变量的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。