1 設計題目與要求 1.1題目: 用多線程同步方法解決生產者-消費者問題(Bounded - Buffer Problem) 1.2目的: 通過研究Linux的線程機制和信號量實現生產者消費者問題的并發控制。 1.3說明: 有界緩沖區內設有20個存儲單元,放入/取出的數據項設定為1-20這20個整型數。 1.4要求: 1.4.1 每個生產者和消費者對有界緩沖區進行操作后,即時顯示有界緩沖區的全部內容、當前指針位置和生產者/消費者線程的標識符。 1.4.2 生產者和消費者各有兩個以上。 1.4.3 多個生產者或多個消費者之間須共享對緩沖區進行操作的函數代碼。 2 總的設計思想 2.1問題描述 生產者-消費者問題是一個經典的進程同步問題,該問題最早由Dijkstra提出,用以演示他提出的信號量機制。在同一個進程地址空間內執行的兩個線程。生產者線程生產物品,然后將物品放置在一個空緩沖區中供消費者線程消費。消費者線程從緩沖區中獲得物品,然后釋放緩沖區。當生產者線程生產物品時,如果沒有空緩沖區可用,那么生產者線程必須等待消費者線程釋放出一個空緩沖區。當消費者線程消費物品時,如果沒有滿的緩沖區,那么消費者線程將被阻塞,直到新的物品被生產出來。 2.2 設計思想 Linux系統下的多線程遵循POSIX線程接口,稱為pthread。編寫Linux下的多線程程序,需要使用頭文件pthread.h,連接時需要使用庫libpthread.a。順便說一下,Linux下pthread的實現是通過系統調用clone()來實現的。clone()是Linux所特有的系統調用,它的使用方式類似fork。 信號量本質上是一個非負的整數計數器,它被用來控制對公共資源的訪問。當公共資源增加時,調用函數sem_post()增加信號量。只有當信號量值大于0時,才能使用公共資源,使用后,函數sem_wait()減少信號量。函數sem_trywait()和函數pthread_ mutex_trylock()起同樣的作用,它是函數sem_wait()的非阻塞版本。下面我們逐個介紹和信號量有關的一些函數,它們都在頭文件/usr/include/semaphore.h中定義。 pthread提供的程序并發控制有: pthread_create() /*創建新的進程*/ pthread_join() /*等待的進程的結束*/ sem_init() /*信號量初始化*/ sem_wait(); /*信號量wait操作*/ sem_post(); /*信號量signal操作*/ phtread_mutex_init() /*互斥量初始化*/ phtread_mutex_lock() /*互斥量P操作*/ pthread_mutex_unck() /*互斥量V操作*/ 3 系統平臺、語言、工具等 系統平臺:linux操作系統 語言: linux下的C語言編程 工具: Linux主機 以及終端 3.1硬件及軟件支持環境 硬件要求不高,普通PC機即可。本程序的開發利用需要PC 裝有linux系統,或者linux終端,他是開發核運行程序的環境。Linux 并發程序支持庫pthread , pthread 是符合POSIX標準的多線程庫。 3.2開發環境 vi 文本編輯 gcc c語言編譯程序 4 數據結構與模塊說明 4.1 數據結構及功能 本程序中的數據結構比較簡單,采用長度為20的數組來存放生產者生產的物品。用數組的下標來表示當前指針的位置。 主程序: int main() { pthread_t p1,p2,p3…..pn,c1,c2,c3……cn; int ret,i; sem_init(&empty,0,MAX); //初始化信號量 sem_init(&full,0,0); sem_init(&mutex,0,1); srand(time(0)); for(i=0;i<MAX;i++) buffer[i]=0; 創建線程: ret = pthread_create(&pn,NULL,producer,(void*)n); //創建生產者線程 if(ret) { printf("create producern error!"); abort(); } ret =pthread_create(&cn,NULL,consumer,(void*)n); //創建消費者線程 if(ret) { printf("create consumern error !"); abort(); } 生產者線程: void *producer(void *threadid) { int i=0; while(1) { sem_wait(&empty); sem_wait(&mutex); ………… sem_post(&mutex); sem_post(&full); } } 消費者線程: void *consumer(void *threadid) { int i=0; while(1) { sem_wait(&full); sem_wait(&mutex); ………… sem_post(&mutex); sem_post(&empty); } } 4.2 流程圖
5 用戶名、源程序名、目標程序名及源程序 主機IP:192.168.1.200 目錄:.../home/j030126/ 用戶名:j030126 源程序名:pro_cus.c 目標程序名:pro_cus 源程序 #include <semaphore.h> #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <time.h> #define MAX 20 int buffer[MAX]; int size=0; sem_t empty, full, mutex; void *producer(void* threadid); void *consumer(void* threadid);
int main() { pthread_t p1,p2,p3,c1,c2,c3; int ret,i; sem_init(&empty,0,MAX); sem_init(&full,0,0); sem_init(&mutex,0,1); srand(time(0)); for(i=0;i<MAX;i++) buffer[i]=0;
ret =pthread_create(&p1,NULL,consumer,(void*)1); if(ret) { printf("create consumer1 error !"); abort(); } ret = pthread_create(&c1,NULL,producer,(void*)1); if(ret) { printf("create producer1 error!"); abort(); } ret =pthread_create(&p2,NULL,consumer,(void*)2); if(ret) { printf("create consumer2 error !"); abort(); } ret = pthread_create(&c2,NULL,producer,(void*)2); if(ret) { printf("create producer2 error!"); abort(); } ret =pthread_create(&p3,NULL,consumer,(void*)3); if(ret) { printf("create consumer3 error !"); abort(); } ret = pthread_create(&c3,NULL,producer,(void*)3); if(ret) { printf("create producer3 error!"); abort(); } pthread_join(p1,NULL); pthread_join(c1,NULL); pthread_join(p2,NULL); pthread_join(c2,NULL); pthread_join(p3,NULL); pthread_join(c3,NULL); }
void *producer(void *threadid) { int i=0; while(1) { sleep(1); sem_wait(&empty); sem_wait(&mutex); buffer[(size++)%MAX]=1; for(i=0;i<MAX;i++) printf("%d",buffer[i]); printf("\nThis is Product %d thread.\n",(int)threadid); sem_post(&mutex); sem_post(&full); sleep(1); } }
void *consumer(void *threadid) { int i=0; while(1) { sleep(rand()%2+1); sem_wait(&full); sem_wait(&mutex); /*buffer[(--size+MAX)%MAX]=0;*/ for(i=0;i<MAX;i++) { if(buffer[i]==1) {buffer[i]=0;break;} printf("%d",buffer[i]); } for(;i<MAX;i++) printf("%d",buffer[i]); printf("\nThis is Customer %d thread.\n",(int)threadid); sem_post(&mutex); sem_post(&empty); sleep(rand()%2+1); } }
6 運行結果與運行情況 本程序運行是隨機的,每次運行的結果是不一樣的,生產者線程和消費者線程是搶占式的運行,生產者線程和消費者線程數分別為3,生產的產品按順序存放在存儲單元,如果存儲單元有產品(顯示為1,無產品則為0),那么消費者按順序消費最先生產出來的產品。這里存在潛在的競爭條件,所謂競爭條件就是這樣一種情況:多個線程對數據產生的作用要依賴于線程的調度順序的。當兩個線程競相訪問同一數據時,就會發生競爭條件。
7 調試報告 7.1調試記錄 本問題主要是實現進程同步和競爭的問題。因此程序最主要的是解決進程間的同步問題。為了清晰地表示出他們的調度過程,需要在調度的同時顯示他們的標識符。緩沖區內容和當前指針位置也要顯示以幫助理解,還可以當程序出錯時幫助分析錯誤原因。另外題目還要求至少要有兩個生產者、兩個消費者。 在這個實例中,首先定義了一個大小為20的公共緩沖區,也就是臨界資源,然后的buffer[MAX]便是緩沖區中產品的數目,初始化為0。producer函數是生產者函數,produce_item(&item);是指生產者生產出來一個產品,但是這時候并沒有對緩沖區進行操作。在這里一開始出現了些小問題,就是在定義變量的時候忘記了格式,所以開始調試程序的時候出現很多提示錯誤,后來再仔細的查看了資料后,才糾正了錯誤的定義方式。if (count==N) sleep();是測試語句,如果生產出來的產品數和緩沖區大小相等時,生產者就進入睡眠狀態。如果不等,產品就放入緩沖區內,并且產品數增加1。if (count==1) wakeup(consumer);這條語句的意思是,如果上一次操作時產品的數目為0,消費者已經進入了睡眠狀態,而現在生產者又生產出來一個產品,緩沖區內不為空,這時把消費者喚醒。消費者函數也是同樣的道理,只不過一個是取,另一個是放。我們可以看到,這里存在潛在的競爭條件,所謂競爭條件就是這樣一種情況:多個線程對數據產生的作用要依賴于線程的調度順序的。當兩個線程競相訪問同一數據時,就會發生競爭條件。由于時間片的原因,一個線程可以在任意一個時刻打斷其他線程,因此數據可能會被破壞或者被錯誤地解釋。還有在編寫代碼時出現了許多常規錯誤如函數名輸入錯誤、變量沒有提前聲明就使用、缺少頭文件等。在整個程序的調試過程中最讓我頭疼的一個問題就是創建線程時數組的指針出了錯,運行時提示有段錯誤,這讓我一開始根本不知道是怎么回事,在求助了同學的基礎上,我查閱了下資料,發現很可能是在指針上出現了問題,仔細研究了程序后,覺得可能是指針在指向地址時由于指向沖突而引起的,所以我把原來的生產者、消費者線程標識符pro、con分別改為proid、conid,以跟生產者和消費者線程子函數名 pro、con 區別開來,避免指針地址同名。然后再次運行程序,終于可以順利執行。 7.2自我評析和總結 在動手實現該程序的過程中,加深了對信號量、線程、等待與同步等重要概念的理解,也提高了自己使用linux編寫C程序的能力。同時,也鍛煉了自己動手解決問題,查閱相關資料的能力.在具體編寫代碼時,通過實踐也認識到養成良好的編碼習慣的重要性.正確的代碼書寫習慣和格式,可以提高程序的可讀性、可調試性。 8 參考文獻 《操作系統概念》 Abraham silberschatz Peter Baer Galvin Greg Gagne 編 高等教育出版社 《操作系統基礎》 屠立德 等編 清華大學出版社
本站部分文章來自網絡,如發現侵犯了您的權益,請聯系指出,本站及時確認刪除 E-mail:349991040@qq.com
論文格式網(www.donglienglish.cn--論文格式網拼音首字母組合)提供其他論文畢業論文格式,論文格式范文,畢業論文范文