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

歡迎訪問 生活随笔!

生活随笔

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

linux

Linux 信号量 生产者消费者小例题

發布時間:2023/12/9 linux 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 信号量 生产者消费者小例题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  菜鳥偶遇信號量,擦出火花(只有不熟才會有火花)。于是上網搜資料和看《Unix環境高級編程》實現了幾個小例題,高手請勿噴!這幾位寫得非常好啊:

題目來源: http://www.it165.net/os/html/201312/7039.html

信號量及其用法:http://www.cnblogs.com/hjslovewcl/archive/2011/03/03/2314341.html

Mutex與Semaphore區別著名的廁所理論:http://koti.mbnet.fi/niclasw/MutexSemaphore.html

?  哎呀,暴露了!我不是故意偷窺別人的……




?

一:一個生產者、一個消費者、一個資源情況

  這種情況情況可以只用一個信號量,要生成或要消費只用嘗試獲取這個信號量,這里用了兩個:full=1和empty=0,兩個只為了和后面一致,1、0是賦初值。生產者和消費者情況如下:

//生產者: P(empty)生成資源并放進資源處 V(full)//消費者: P(full)消費資源 V(empty)

  若生產者最先開始生產資源,P(empty),full和empty都成了0,此時若消費者想要消費,則P(full)時,full為0則睡眠等待,等生產者生結束就把full加1,看到消費者可憐地睡著了就喚醒它,然后消費者把full減1自己快活去了。

  消費者消費過程中生產者若要生了,則會因為empty為0而休眠,等消費者結束就把empty加1,然后生產者開始生產。

  上面的好理解,下面上代碼:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h>#include <x86_64-linux-gnu/sys/types.h> #include <x86_64-linux-gnu/sys/ipc.h> #include <x86_64-linux-gnu/sys/sem.h>int semInite(int semId, int value); int semDelete(int semId); int semP(int semId); int semV(int semId);//declare a union to be used union semun {int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ };//semaphore declare static int semFullId; static int semEmptyId; static int source = 0; //source definition //new thread as a consumer void* child_thread(void* arg) {int ttt = 1;while(1){sleep(rand() % 19);printf("child No.%d times wants to consume...\n", ttt);semP(semFullId); // printf("child No.%d times start consuming. source = %d\n", ttt, source);source = 0;printf("child No.%d times end consuming. source = %d\n\n", ttt++, source);semV(semEmptyId); // }return (void*)0; }int main(void) { //create semaphoresemFullId = semget((key_t)1235, 1, 0666 | IPC_CREAT);semEmptyId = semget((key_t)1236, 1, 0666 | IPC_CREAT);semInite(semFullId, 0);semInite(semEmptyId, 1);pthread_t pid;pthread_create(&pid, NULL, child_thread, NULL);int tt = 1; while(1){sleep(rand() % 18);printf("parent No.%d times wants to produce...\n", tt);semP(semEmptyId); // printf("parent No.%d times start producing. source = %d\n", tt, source);source = rand() % 100;printf("parent No.%d times end producing. source = %d\n", tt++, source);semV(semFullId); // }semDelete(semFullId);semDelete(semEmptyId);return 0; }//set semaphore as default value int semInite(int semId, int value) {union semun semUnion;semUnion.val = value; //set default semaphorereturn semctl(semId, 0, SETVAL, semUnion); }//delete semaphore int semDelete(int semId) {union semun semUnion;return semctl(semId, 0, IPC_RMID, semUnion); }//semaphore P operation int semP(int semId) {struct sembuf semBuf;semBuf.sem_num = 0; //indicate it is not semaphore arraysemBuf.sem_op = -1; //subtract onesemBuf.sem_flg = SEM_UNDO;return semop(semId, &semBuf, 1); //return value }//semaphore V operation int semV(int semId) {struct sembuf semBuf;semBuf.sem_num = 0; //indicate it is not semaphore arraysemBuf.sem_op = 1; //subtract onesemBuf.sem_flg = SEM_UNDO;return semop(semId, &semBuf, 1); //return value } 111

兩個信號量其實應該用信號量集的,因為它本來就是針對集合的,但是由于剛入門,為了易懂,就用兩個。兩個線程,創建的新線程當做消費者了。其中unix的幾個信號量的函數看了半天,有點復雜,簡單不準確來講:

//獲得一個信號量啦,第二個參數是想要創建的信號量個數, //因為unix操作的是信號量集合,設為1不就一個信號量了嘛 //其他參數我不管了 int semget(key_t key, int num_sems, int sem_flags);//信號量集合的操作,這個可以用來實現P、V的 +1 -1 的功能 int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);//信號量集合的控制,如初始化刪除等 int semctl(int sem_id, int sem_num, int command, ...);

運行:




?

二:一個生產者、一個消費者、N個資源情況

  這里資源用是一個數組代替了。其實本質上和上面類似,每次只讓生產者或消費者中的一個進入,進入后放到哪個地方或從哪個地方取就得用一個標志來說明了,其實也可以為每一資源加上信號量的。

  這里在生產者和消費者那里都設置了一個static的變量當做游標,指示下個資源放到哪個位置和下次從哪取資源。staitic變量用在這里很合適,因為只會初始化一次。

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h>#include <x86_64-linux-gnu/sys/types.h> #include <x86_64-linux-gnu/sys/ipc.h> #include <x86_64-linux-gnu/sys/sem.h>#define N 5int semInite(int semId, int value); int semDelete(int semId); int semP(int semId); int semV(int semId);//declare a union to be used union semun {int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ };//semaphore declare static int semFullId; static int semEmptyId; static int srcArr[N]; //source definition //new thread as a consumer void* child_thread(void* arg) {int ttt = 1;while(1){static int pToGet = 0; //get source from the positionsleep(rand() % 19);printf("child No.%d times wants to consume(get from index %d)...\n", ttt, pToGet);semP(semFullId); // printf("child No.%d times start consuming.(get from index %d, data is %d)\n", ttt, pToGet, srcArr[pToGet]);srcArr[pToGet] = 0;printf("child No.%d times end consuming. (get from index %d)\n\n", ttt++, pToGet);pToGet = (pToGet + 1) % N;semV(semEmptyId); // }return (void*)0; }int main(void) { //create semaphoresemFullId = semget((key_t)1235, 1, 0666 | IPC_CREAT);semEmptyId = semget((key_t)1236, 1, 0666 | IPC_CREAT);semInite(semFullId, 0);semInite(semEmptyId, N); //N source pthread_t pid;pthread_create(&pid, NULL, child_thread, NULL);int tt = 1; while(1){static int pToPut = 0; //next position where source to be filled insleep(rand() % 18);printf("parent No.%d times wants to produce(put in %d index)...\n", tt, pToPut);semP(semEmptyId); // printf("parent No.%d times start producing.(put in %d index, original data is %d)\n", tt, pToPut, srcArr[pToPut]);int temp = rand() % 100;srcArr[pToPut] = temp;printf("parent No.%d times end producing.(put in %d index, now data is %d)\n", tt++, pToPut, srcArr[pToPut]);pToPut = (pToPut + 1) % N;semV(semFullId); // }semDelete(semFullId);semDelete(semEmptyId);return 0; }//set semaphore as default value int semInite(int semId, int value) {union semun semUnion;semUnion.val = value; //set default semaphorereturn semctl(semId, 0, SETVAL, semUnion); }//delete semaphore int semDelete(int semId) {union semun semUnion;return semctl(semId, 0, IPC_RMID, semUnion); }//semaphore P operation int semP(int semId) {struct sembuf semBuf;semBuf.sem_num = 0; //indicate it is not semaphore arraysemBuf.sem_op = -1; //subtract onesemBuf.sem_flg = SEM_UNDO;return semop(semId, &semBuf, 1); //return value }//semaphore V operation int semV(int semId) {struct sembuf semBuf;semBuf.sem_num = 0; //indicate it is not semaphore arraysemBuf.sem_op = 1; //subtract onesemBuf.sem_flg = SEM_UNDO;return semop(semId, &semBuf, 1); //return value } 222

運行結果:




?

三:N個生產者,N個消費者,N個資源

?  這種情況不僅生產者和消費者之間要通過上述的方式協調使用資源,而且生產者內部和消費者內部也要協調。定義四個信號量:

empty——表示緩沖區是否為空,初值為n。
full——表示緩沖區中是否為滿,初值為0。
mutex1——生產者之間的互斥信號量,初值為1。
mutex2——消費者之間的互斥信號量,初值為1。

//生產者進程 P(mutex1)P(empty)生產數據并放進特定位置V(full) V(mutex1)//消費者進程 P(mutex2)P(full)消費數據V(empty) V(mutex2)

其實上面生產者或者消費者獲取互斥量或信號量的順序可以顛倒的,不會產生死鎖。

  當然這個問題可以用其他更好的方式解決,我還得繼續學習。

轉載于:https://www.cnblogs.com/jiayith/p/3854312.html

總結

以上是生活随笔為你收集整理的Linux 信号量 生产者消费者小例题的全部內容,希望文章能夠幫你解決所遇到的問題。

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