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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux——线程通信(2)

發布時間:2024/7/19 linux 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux——线程通信(2) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 1.條件變量
    • 1.1 條件變量函數:
    • 1.2 pthread_cond_init 函數
    • 1.3 pthread_cond_destroy 函數
    • 1.4 pthread_cond_wait 函數
    • 1.5 pthread_cond_timedwait 函數
    • 1.6 pthread_cond_signal 函數
    • 1.7 pthread_cond_broadcast 函數
  • 2.生產者消費者模型
  • 3.條件變量的優點:
  • 4.信號量
  • 5.信號量函數:
    • 5.1 信號量基本操作:
    • 5.2 sem_init 函數
    • 5.3 sem_destroy 函數
    • 5.4 sem_wait 函數
    • 5.5 sem_post 函數
    • 5.6 sem_trywait 函數
    • 5.7 sem_timedwait 函數
  • 6.信號量舉例
  • 7.生產者消費者信號量模型
  • 8.哲學家吃飯問題
  • 9.共享內存

1.條件變量

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

1.1 條件變量函數:

pthread_cond_init 函數 pthread_cond_destroy 函數 pthread_cond_wait 函數 pthread_cond_timedwait 函數 pthread_cond_signal 函數 pthread_cond_broadcast 函數 以上 6 個函數的返回值都是:成功返回 0, 失敗直接返回錯誤號。 pthread_cond_t 類型 用于定義條件變量 pthread_cond_t cond;

1.2 pthread_cond_init 函數

初始化一個條件變量

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); 參 2:attr 表條件變量屬性,通常為默認值,傳 NULL 即可 也可以使用靜態初始化的方法,初始化條件變量: pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

1.3 pthread_cond_destroy 函數

銷毀一個條件變量

int pthread_cond_destroy(pthread_cond_t *cond);

1.4 pthread_cond_wait 函數

阻塞等待一個條件變量

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

函數作用:

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

    限時等待一個條件變量

    int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); 參 3: 參看 man sem_timedwait 函數,查看 struct timespec 結構體。 struct timespec {time_t tv_sec; /* seconds */long tv_nsec; /* nanosecondes*/ 納秒 } 形參 abstime:絕對時間。 如:time(NULL)返回的就是絕對時間。而 alarm(1)是相對時間,相對當前時間定時 1 秒鐘。struct timespec t = {1, 0}; pthread_cond_timedwait (&cond, &mutex, &t); 只能定時到 1970 年 1 月 1 日 00:00:01 秒(早已經過去)正確用法: time_t cur = time(NULL); 獲取當前時間。 struct timespec t; 定義 timespec 結構體變量 t t.tv_sec = cur+1; 定時 1 秒 pthread_cond_timedwait (&cond, &mutex, &t); 傳參 參 APUE.11.6 線程同步條件變量小節 在講解 setitimer 函數時我們還提到另外一種時間類型: struct timeval {time_t tv_sec; /* seconds */ 秒suseconds_t tv_usec; /* microseconds */ 微秒};

    1.6 pthread_cond_signal 函數

    喚醒至少一個阻塞在條件變量上的線程

    int pthread_cond_signal(pthread_cond_t *cond);

    1.7 pthread_cond_broadcast 函數

    喚醒全部阻塞在條件變量上的線程

    int pthread_cond_broadcast(pthread_cond_t *cond);

    2.生產者消費者模型

    線程同步典型的案例即為生產者消費者模型,而借助條件變量來實現這一模型,是比較常見的一種方法。 假定有兩個線程,一個模擬生產者行為,一個模擬消費者行為。 兩個線程同時操作一個共享資源(一般稱之為匯聚),生產向其中添加產品,消費者從中消費掉產品。 #include <stdlib.h> #include <unistd.h> #include <pthread.h> struct msg {struct msg *next;int num; }; struct msg *head; pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;void *consumer(void *p) {struct msg *mp;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) {struct msg *mp;while (1) {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(int argc, char *argv[]) {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; } zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_cond -Produce ---425 -Consume ---425 -Produce ---486 -Consume ---486 -Produce ---699 -Consume ---699 -Produce ---736 -Consume ---736 -Produce ---452 -Consume ---452 -Produce ---529 -Consume ---529 -Produce ---664 -Consume ---664 -Produce ---340 -Consume ---340 ^C

    3.條件變量的優點:

    相較于 mutex 而言,條件變量可以減少競爭。 如直接使用 mutex,除了生產者、消費者之間要競爭互斥量以外, 消費者之間也需要競爭互斥量,但如果匯聚(鏈表)中沒有數據,消費者之間競爭互斥鎖是無意義的。 有了條件變量機制以后,只有生產者完成生產,才會引起消費者之間的競爭。提高了程序效率。

    4.信號量

    進化版的互斥鎖(1 --> N) 由于互斥鎖的粒度比較大,如果我們希望在多個線程間對某一對象的部分數據進行共享, 使用互斥鎖是沒有辦法實現的,只能將整個數據對象鎖住。 這樣雖然達到了多線程操作共享數據時保證數據正確性的目的,卻無形中導致線程的并發性下降。 線程從并行執行,變成了串行執行。與直接使用單進程無異。 信號量,是相對折中的一種處理方式,既能保證同步,數據不混亂,又能提高線程并發。

    5.信號量函數:

    sem_init 函數 sem_destroy 函數 sem_wait 函數 sem_trywait 函數 sem_timedwait 函數 sem_post 函數 以上 6 個函數的返回值都是:成功返回 0, 失敗返回-1,同時設置 errno。(注意,它們沒有 pthread 前綴) sem_t 類型,本質仍是結構體。但應用期間可簡單看作為整數,忽略實現細節(類似于使用文件描述符)。 sem_t sem; 規定信號量 sem 不能 < 0。頭文件 <semaphore.h>

    5.1 信號量基本操作:

    sem_wait: 1. 信號量大于 0,則信號量-- (類比 pthread_mutex_lock)2. 信號量等于 0,造成線程阻塞 sem_post: 將信號量++,同時喚醒阻塞在信號量上的線程 (類比 pthread_mutex_unlock) 但,由于 sem_t 的實現對用戶隱藏,所以所謂的++、--操作只能通過函數來實現,而不能直接++、--符號。 信號量的初值,決定了占用信號量的線程的個數。

    5.2 sem_init 函數

    初始化一個信號量

    int sem_init(sem_t *sem, int pshared, unsigned int value); 參 1:sem 信號量 參 2:pshared 取 0 用于線程間;取非 0(一般為 1)用于進程間 參 3:value 指定信號量初值

    5.3 sem_destroy 函數

    銷毀一個信號量

    int sem_destroy(sem_t *sem);

    5.4 sem_wait 函數

    給信號量加鎖 –

    int sem_wait(sem_t *sem);

    5.5 sem_post 函數

    給信號量解鎖 ++

    int sem_post(sem_t *sem);

    5.6 sem_trywait 函數

    嘗試對信號量加鎖 – (與 sem_wait 的區別類比 lock 和 trylock)

    int sem_trywait(sem_t *sem);

    5.7 sem_timedwait 函數

    限時嘗試對信號量加鎖 –

    int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); 參 2:abs_timeout 采用的是絕對時間。 定時 1 秒: time_t cur = time(NULL); 獲取當前時間。 struct timespec t; 定義 timespec 結構體變量 t t.tv_sec = cur+1; 定時 1 秒 t.tv_nsec = t.tv_sec +100; sem_timedwait(&sem, &t); 傳參

    6.信號量舉例

    #include<stdio.h> #include <semaphore.h> #include<stdlib.h> #include<pthread.h> #include<unistd.h>sem_t sem; void *func(void* arg){int i=(int)arg;while(1){sem_wait(&sem);printf("我是%d,我正在吃飯,當前座位剩余:%d\n",i,sem);sleep(2);sem_post(&sem);sleep(4);}return NULL; }int main() {pthread_t tid[10];sem_init(&sem,0,5);int i;for(i=0;i<10;i++){pthread_create(&tid[i],NULL,func,(void*)i);}for(i=0;i<10;i++){pthread_join(tid[i],NULL);}sem_destroy(&sem);return 0; } zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./sem 我是0,我正在吃飯,當前座位剩余:4 我是1,我正在吃飯,當前座位剩余:3 我是2,我正在吃飯,當前座位剩余:2 我是3,我正在吃飯,當前座位剩余:1 我是4,我正在吃飯,當前座位剩余:0 我是5,我正在吃飯,當前座位剩余:1 我是8,我正在吃飯,當前座位剩余:2 我是6,我正在吃飯,當前座位剩余:0 我是7,我正在吃飯,當前座位剩余:1 我是9,我正在吃飯,當前座位剩余:0 我是0,我正在吃飯,當前座位剩余:4 我是4,我正在吃飯,當前座位剩余:2 我是1,我正在吃飯,當前座位剩余:3 我是3,我正在吃飯,當前座位剩余:1 我是2,我正在吃飯,當前座位剩余:0 ^C

    7.生產者消費者信號量模型

    使用信號量完成線程間同步,模擬生產者,消費者問題。

    【sem_product_consumer.c】 規定: 如果□中有數據,生產者不能生產,只能阻塞。如果□中沒有數據,消費者不能消費,只能等待數據。定義兩個信號量:S 滿 = 0, S 空 = 1 (S 滿代表滿格的信號量,S 空表示空格的信號量,程序起始,格子一定為空)

    所以有:

    T 生產者主函數 { sem_wait(S 空); //空格減1生產....sem_post(S 滿); //大餅加1 } T 消費者主函數 {sem_wait(S 滿);//大餅減1消費....sem_post(S 空);//空格加1} 假設: 線程到達的順序是:T 生、T 生、T 消。 那么: T 生 1 到達,將 S 空-1,生產,將 S 滿+1 T 生 2 到達,S 空已經為 0, 阻塞 T 消 到達,將 S 滿-1,消費,將 S 空+1三個線程到達的順序是:T 生 1、T 生 2、T 消。而執行的順序是 T 生 1、T 消、T 生 2 這里,S 空 表示空格子的總數,代表可占用信號量的線程總數-->1。其實這樣的話,信號量就等同于互斥鎖。 但,如果 S 空=2、3、4……就不一樣了,該信號量同時可以由多個線程占用,不再是互斥的形式。 因此我們說信號量是互斥鎖的加強版。

    8.哲學家吃飯問題

    讓所有哲學家聽到吃飯口令之后,都拿自己右手邊的筷子,但是選定某一個哲學家A必須拿自己左手邊的筷子; 這樣子,A哲學家右邊的哲學家B肯定可以第一個吃到飯,吃完飯放下筷子,下面一個人就可以吃飯了; 以此類推。。。

    9.共享內存

    #include<stdio.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h>int a=10; void* func(void* arg) {sleep(1);a=100;printf("我要修改a\n");sleep(2);return NULL; } int main() {pthread_t tid;pthread_create(&tid,NULL,func,NULL);while(1){printf("%d\n",a);sleep(1);}pthread_join(tid,NULL);return 0; } zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_com 10 我要修改a 100 100 100 100 100 100 100 ^C 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的linux——线程通信(2)的全部內容,希望文章能夠幫你解決所遇到的問題。

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