Linux入門之POSIX線程原語

1. POSIX簡介

POSIX表示可移植操作系統(tǒng)接口(Portable Operating System Interface of UNIX鸽斟,縮寫為POSIX),POSIX標(biāo)準(zhǔn)定義了操作系統(tǒng)為應(yīng)用程序提供的接口標(biāo)準(zhǔn)利诺。
這里介紹的是關(guān)于POSIX線程的內(nèi)容富蓄,POSIX線程的API都在pthread.h文件中,如果已經(jīng)安裝了慢逾,可以通過以下命令查看所有API:

man -k pthread

查看某個API的用法:

man pthread_create

如果沒有安裝立倍,可以通過以下命令去安裝POSIX文檔:

sudo apt-get install manpages-posix-dev

2. 創(chuàng)建線程與線程結(jié)束:

新建01.c文件:

  1 #include<stdlib.h>
  2 #include<stdio.h>
  3 #include<unistd.h>
  4 #include<pthread.h>
  5 
  6 void* thr_fun(void* arg) {
  7     char* no = (char*)arg;
  8     int i = 0;
  9     for(; i < 10; i++) {
 10         printf("thread:%s,i:%d\n", no, i);
 11         if(i == 5) {
 12             //線程結(jié)束(自殺)                                                                                                                                         
 13             pthread_exit((void*)2);
 14         }
 15     }
 16     return (void*)1;
 17 }
 18 
 19 void main() {
 20     printf("man thread\n");
 21     //線程的id
 22     pthread_t tid;
 23     //第二個參數(shù)表示屬性灭红,NULL表示默認(rèn)屬性
 24     //thr_fun,線程創(chuàng)建之后執(zhí)行的函數(shù)
 25     pthread_create(&tid, NULL, thr_fun, "1");
 26     void* retval;
 27     //等待tid線程結(jié)束
 28     //thr_fun與pthread_exit退出時的參數(shù)口注,都作為第二個參數(shù)的內(nèi)容
 29     pthread_join(tid, &retval);
 30     printf("retval:%d\n", (int)retval);
 31 }

上述線程自殺用pthread_exit()变擒,而線程他殺用pthread_cancel()
將01.c文件編譯成可執(zhí)行文件:

gcc 01.c -o 01 -lpthread

這時候在該目錄下生成01文件,此時我們就可以執(zhí)行該文件了:

./01

輸出為:

man thread
thread:1,i:0
thread:1,i:1
thread:1,i:2
thread:1,i:3
thread:1,i:4
thread:1,i:5
retval:2

3. 互斥鎖的使用

新建02.c文件:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<pthread.h>
  5 
  6 int i = 0;
  7 //互斥鎖
  8 pthread_mutex_t mutex;
  9 void* thr_fun(void* arg) {
 10     //加鎖
 11     pthread_mutex_lock(&mutex);
 12     char* no = (char*)arg;
 13     for(; i < 5; i++) {
 14         printf("thread:%s寝志,i:%d\n", no, i);
 15         sleep(1);
 16     }
 17     i = 0;
 18     //解鎖
 19     pthread_mutex_unlock(&mutex);
 20 }
 21 
 22 void main() {
 23     pthread_t tid1, tid2;
 24     //初始化互斥鎖
 25     pthread_mutex_init(&mutex, NULL);
 26 
 27     pthread_create(&tid1, NULL, thr_fun, "NO1");
 28     pthread_create(&tid2, NULL, thr_fun, "NO2");
 29 
 30     pthread_join(tid1, NULL);
 31     pthread_join(tid2, NULL);
 32     
 33     //銷毀互斥鎖
 34     pthread_mutex_destroy(&mutex);
 35 }  

上面的代碼中:

  1. 我們通過pthread_mutex_init先初始化互斥鎖娇斑,再通過創(chuàng)建NO1線程和NO2線程,通過pthread_join去阻塞主線程材部,直到子線程結(jié)束毫缆,最后銷毀互斥鎖
  2. 在某個線程執(zhí)行的時候,首先通過pthread_mutex_lock加鎖乐导,當(dāng)該線程執(zhí)行完了之后苦丁,再通過pthread_mutex_unlock釋放鎖,讓另外的一個線程去加鎖物臂。
  3. 互斥鎖就是將一個線程做完旺拉,然后另一個線程再做。

編譯02.c文件:

gcc 02.c -o 02 -lpthread

運行02文件:

thread:NO2鹦聪,i:0
thread:NO2账阻,i:1
thread:NO2,i:2
thread:NO2泽本,i:3
thread:NO2淘太,i:4
thread:NO1,i:0
thread:NO1规丽,i:1
thread:NO1蒲牧,i:2
thread:NO1,i:3
thread:NO1赌莺,i:4

可以發(fā)現(xiàn)冰抢,先將線程NO2執(zhí)行完了,才會執(zhí)行線程NO1艘狭,這就是互斥鎖的作用所在挎扰。

我在shell5中查找pthread_create是可以查到用法的,但是我查找pthread_mutex_init中是無法查找的巢音,也試過先更新sudo遵倦,再使用下面的命令下載也不行:

sudo apt-get install manpages-posix-dev

后來發(fā)現(xiàn)這是man不完整的原因,利用下列命令去下載完整版:

sudo apt-get update

安裝標(biāo)準(zhǔn)C的幫助文檔

sudo apt-get install libc-dev
sudo apt-get install glibc-doc

下載過程中遇到y(tǒng)/n官撼,一律輸入y進行下載梧躺。最后查看pthread_mutex_init就可以了

man pthread_mutex_init

4. 生產(chǎn)者、消費者模型

上面我們已經(jīng)了解了互斥鎖的用法了傲绣,接下來我們用互斥鎖和條件變量來實現(xiàn)生產(chǎn)者掠哥、消費者模型巩踏。
其實視頻解碼的繪制使用就是生產(chǎn)者--消費者模型。圖片的下載顯示也是基于這種模型续搀。比如說我們生產(chǎn)者生成的產(chǎn)品塞琼,放到一個隊列里面,當(dāng)生產(chǎn)者生產(chǎn)出產(chǎn)品的時候就會發(fā)送信號通知消費者去消費目代,例如RTMP推流的時候屈梁,我們本地采集音視頻的時候就需要一種隊列捣染,因為本地的壓縮比網(wǎng)絡(luò)上傳要快姊氓。

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<pthread.h>
  5 
  6 //互斥鎖
  7 pthread_mutex_t mutex;
  8 //條件變量
  9 pthread_cond_t has_product;
 10 //隊列
 11 int ready;
 12 
 13 //生產(chǎn)著
 14 void* thr_producer(void* arg) {
 15     int no = (int)arg;
 16     for(;;) {
 17         //加鎖
 18         pthread_mutex_lock(&mutex);
 19         //往隊列中添加產(chǎn)品
 20         ready++;
 21         printf("producer %d produce\n", no);
 22         //通知消費者,有新的產(chǎn)品可以消費了
 23         pthread_cond_signal(&has_product);
 24         //解鎖
 25         pthread_mutex_unlock(&mutex);
 26         sleep(1);
 27       }
 28    }
 29
 30 void* thr_consumer(void* arg) {
 33         pthread_mutex_lock(&mutex);
 34         if(ready == 0) {
 35             //沒有產(chǎn)品狼钮,繼續(xù)等待
 36             pthread_cond_wait(&has_product, &mutex);
 37             printf("consumer %d wait\n", no);
 38         }
 39         //有產(chǎn)品霜大,消費產(chǎn)品
 40         ready--;
 41         printf("consumer %d consume\n", no);
 42         sleep(1);
 43         pthread_mutex_unlock(&mutex);
 44     }
 45 }
 46 
 47 void main() {
 48     //初始化互斥鎖和條件變量
 49     pthread_mutex_init(&mutex, NULL);
 50     pthread_cond_init(&has_product, NULL);
 51 
 52     pthread_t tid_p, tid_c;
 53     //生產(chǎn)者線程
 54     pthread_create(&tid_p, NULL, thr_producer, 1);
 55     //消費者線程
 56     pthread_create(&tid_c, NULL, thr_consumer, 2);
 57     
 58     //等待
 59     pthread_join(tid_p, NULL);
 60     pthread_join(tid_c, NULL);
 61 
 62     //銷毀
 63     pthread_mutex_destroy(&mutex);
 64     pthread_cond_destroy(&has_product);
 65 }

上面的代碼中我們創(chuàng)建了兩個線程构哺,分別是生產(chǎn)者線程和消費者線程,生產(chǎn)者線程循環(huán)添加產(chǎn)品战坤,添加完了之后通過消費者去消費曙强,消費者發(fā)現(xiàn)有產(chǎn)品就消費產(chǎn)品,沒有產(chǎn)品途茫,就繼續(xù)等待碟嘴,兩個線程都是利用互斥鎖保證本身線程的執(zhí)行。

但是這樣單獨一個生產(chǎn)者線程和消費者線程顯然是不夠的囊卜,實際使用中往往是多個生產(chǎn)者線程和消費者線程娜扇,接下來我將循環(huán)產(chǎn)生多個生產(chǎn)者線程和消費者線程:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<pthread.h>
  5 #define PRODUCER_NUM 1
  6 #define CONSUMER_NUM 2
  7 pthread_t pids[PRODUCER_NUM + CONSUMER_NUM];
  8 //互斥鎖
  9 pthread_mutex_t mutex;
 10 //條件變量
 11 pthread_cond_t has_product;
 12 
 13 //產(chǎn)品隊列
 14 int ready = 0;
 15 
 16 //生產(chǎn)者
 17 void* thr_producer(void* arg) {
 18     int no = (int)arg;
 19     for(;;) {
 20         //加鎖
 21         pthread_mutex_lock(&mutex);
 22         //往隊列中添加產(chǎn)品
 23         ready++;
 24         printf("producer %d produce\n", no);
 25         //通知消費者,有新的產(chǎn)品可以消費了
 26         pthread_cond_signal(&has_product);
 27         //解鎖
 28         pthread_mutex_unlock(&mutex);
 29         sleep(1);
 30     }
 31 }
 32 
 33 //消費者
 34 void* thr_consumer(void* arg) {
 35     int no = (int)arg;
 36     for(;;) {
 37         //加鎖
 38         pthread_mutex_lock(&mutex);
 39         while(ready == 0) {
 40             printf("consumer %d wait\n", no);
 41             //沒有產(chǎn)品栅组,繼續(xù)等待
 42             //1.阻塞 等待has_product被喚醒
 43             //2.釋放互斥鎖雀瓢,pthread_mutex_unlock
 44             //3.被喚醒時,解除阻塞玉掸,重新申請獲得互斥鎖 pthread_mutex_lock
 45             pthread_cond_wait(&has_product, &mutex);
 46         }
 47         //有產(chǎn)品刃麸,消費產(chǎn)品
 48         ready--;
 49         printf("consumer %d consume\n", no);
 50         //解鎖
 51         pthread_mutex_unlock(&mutex);
 52         sleep(3);
 53     }
 54 }
 55 
 56 void main() {
 57     //初始化互斥鎖和條件變量
 58     pthread_mutex_init(&mutex, NULL);
 59     pthread_cond_init(&has_product, NULL);
 60     int i = 0;
 61     for(; i < PRODUCER_NUM; i++) {
 62         //生產(chǎn)者線程
 63         pthread_create(&pids[i], NULL, thr_producer, (void*)i);
 64     }
 65     
 66     i = 0;
 67     for(; i < CONSUMER_NUM; i++) {
 68         //消費者線程
 69         pthread_create(&pids[PRODUCER_NUM + i], NULL, thr_consumer, (void*)i);
 70     }
 71 
 72     i = 0;
 73     for(; i < PRODUCER_NUM + CONSUMER_NUM; i++) {
 74         //等待
 75         pthread_join(pids[i], NULL);
 76     }
 77     
 78     //銷毀互斥鎖和條件變量
 79     pthread_mutex_destroy(&mutex);
 80     pthread_cond_destroy(&has_product);
 81 }

編譯生成可執(zhí)行文件:

gcc 03.c -o 03 -lpthread

執(zhí)行文件:

./03

執(zhí)行后終端截圖如下:

1.png

可以按Ctrl + c停止。

喜歡本篇博客的簡友們司浪,就請來一波點贊泊业,您的每一次關(guān)注,將成為我前進的動力啊易,謝謝脱吱!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市认罩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌续捂,老刑警劉巖垦垂,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宦搬,死亡現(xiàn)場離奇詭異,居然都是意外死亡劫拗,警方通過查閱死者的電腦和手機间校,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來页慷,“玉大人憔足,你說我怎么就攤上這事【品保” “怎么了滓彰?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長州袒。 經(jīng)常有香客問我揭绑,道長,這世上最難降的妖魔是什么郎哭? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任他匪,我火速辦了婚禮,結(jié)果婚禮上夸研,老公的妹妹穿的比我還像新娘邦蜜。我一直安慰自己,他們只是感情好亥至,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布悼沈。 她就那樣靜靜地躺著,像睡著了一般抬闯。 火紅的嫁衣襯著肌膚如雪井辆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天溶握,我揣著相機與錄音杯缺,去河邊找鬼。 笑死睡榆,一個胖子當(dāng)著我的面吹牛萍肆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胀屿,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼塘揣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宿崭?” 一聲冷哼從身側(cè)響起亲铡,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后奖蔓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赞草,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年吆鹤,在試婚紗的時候發(fā)現(xiàn)自己被綠了厨疙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡疑务,死狀恐怖沾凄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情知允,我是刑警寧澤撒蟀,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站廊镜,受9級特大地震影響牙肝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嗤朴,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一配椭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧雹姊,春花似錦股缸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至歧杏,卻和暖如春镰惦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背犬绒。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工旺入, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凯力。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓茵瘾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咐鹤。 傳聞我的和親對象是個殘疾皇子拗秘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容