- 1. 實驗目的
兩個或兩個以上的進程,不能同時進入關於同一組共享變量的臨界區域,否則可能發生與時間有關的錯誤,這種現象被稱作進程互斥。對CPU的速度和數目不做出任何假設的前提下,並發進程互斥訪問臨界資源,是一個較好的解決方案。另外,還需要解決異步環境下的進程同步問題。所謂異步環境是指:相互合作的一組並發進程,其中每一個進程都以各自獨立的、不可預知的速度向前推進;但它們又需要密切合作,以實現一個共同的任務,即彼此“知道”相互的存在和作用。
實驗目的:分析進程爭用資源的現象,學習解決進程同步與互斥的方法。
本實驗屬於設計型實驗,實驗者可根據自身情況選用合適的開發環境和程序架構。
- 2. 實驗原理
信號量的PV操作與處理相關,P表示通過的意思,V表示釋放的意思。
1962年,狄克斯特拉離開數學中心進入位於荷蘭南部的艾恩德霍芬技術大學(Eindhoven Technical University)任數學教授。在這里,他參加了X8計算機的開發,設計與實現了具有多道程序運行能力的操作系統——THE Multiprogramming System。THE是艾恩德霍芬技術大學的荷蘭文Tchnische Hoogeschool Eindhov –en的詞頭縮寫。狄克斯特拉在THE這個系統中所提出的一系統方法和技術奠定了計算機現代操作系統的基礎,尤其是關於多層體系結構,順序進程之間的同步和互斥機制這樣一些重要的思想和概念都是狄克斯特拉在THE中首先提出並為以后的操作系統如UNIX等所采用的。
為了在單處理機的情況下確定進程(process)能否占有處理機,狄克斯特拉將每個進程分為“就緒”(ready)、“運行”(running)和“阻塞”(blocking)三個工作狀態。由於在任一時刻最多只有一個進程可以使用處理機,正占用着處理機的進程稱為“運行”進程。當某進程已具備了使用處理機的條件,而當前又沒有處理機供其使用,則使該進程處於“就緒”狀態。當運行進程由於某種原因無法繼續運行下去時,就停止其占用處理機,使之進入“阻塞”狀態,待造成其退出運行的條件解除,再進入“就緒”狀態。而對系統中所有同時運行的進程(在一個進程訪問共享數據時,另一個進程不訪問該數據),存在同步和互斥(mutually- exclusive,指兩個進程不能同時在一個臨界區中使用同一個可重復使用的資源,諸如讀寫緩沖區)兩個關系,狄克斯特拉巧妙地利用火車運行控制系統中的“信號量”(semaphore,或叫”信號燈”)概念加以解決。
所謂信號量,實際上就是用來控制進程狀態的一個代表某一資源的存儲單元。例如,P1和P2是分別將數據送入緩沖B和從緩沖B讀出數據的兩個進程,為了防止這兩個進程並發時產生錯誤,狄克斯特拉設計了一種同步機制叫“PV操作”,P操作和V操作是執行時不被打斷的兩個操作系統原語。執行P操作P(S)時信號量S的值減1,若結果不為負則P(S)執行完畢,否則執行P操作的進程暫停以等待釋放。執行V操作V(S)時,S的值加1,若結果不大於0則釋放一個因執行P(S)而等待的進程。對P1和P2可定義兩個信號量S1和S2,初值分別為1和0。進程P1在向緩沖B送入數據前執行P操作P(S1),在送入數據后執行V操作V(S2)。進程P2在從緩沖B讀取數據前先執行P操作P(S2),在讀出數據后執行V操作V(S1)。當P1往緩沖B送入一數據后信號量S1之值變為0,在該數據讀出后S1之值才又變為1,因此在前一數未讀出前后一數不會送入,從而保證了P1和P2之間的同步。
這一同步機制叫PV操作,這是狄克斯特拉用荷蘭文定義的,因為在荷蘭文中,通過叫passeren,釋放叫vrijgeven,PV操作因此得名。這是在計算機術語中不是用英語表達的極少數的例子之一。
- 3. 實驗內容
以下是進程同步與互斥的典型問題例析——生產者消費者,請模擬它的實現過程。
問題描述:一個倉庫可以存放K件物品。生產者每生產一件產品,將產品放入倉庫,倉庫滿了就停止生產。消費者每次從倉庫中去一件物品,然后進行消費,倉庫空時就停止消費。
數據結構:進程:Producer - 生產者進程,Consumer - 消費者進程
buffer: array [0..k-1] of integer;
in,out: 0..k-1;
in記錄第一個空緩沖區,out記錄第一個不空的緩沖區
s1,s2,mutex: semaphore;
s1控制緩沖區不滿,s2控制緩沖區不空,mutex保護臨界區;
初始化s1=k,s2=0,mutex=1
4. 實驗步驟
i. 選用合適的實驗程序開發環境。
ii. 設計程序結構,規划程序功能。
iii. 完成程序的編碼與測試。
iv. 設計實驗數據。
v. 針對實驗數據運行程序,並將結果記錄在實驗報告上。
5. 代碼:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <pthread.h> #include <unistd.h> #include <signal.h> #include <semaphore.h> #define Maxbuf 10 #define TimesOfOp 10 #define true 1 #define false 0 struct Circlebuf { int read; int write; int buf[Maxbuf]; } circlebuf; sem_t mutex;// sem_t empty;// sem_t full;// void writeCirclebuf(struct Circlebuf *circlebuf, int *value) { circlebuf->buf[circlebuf->write] = (*value); circlebuf->write=(circlebuf->write+1)%Maxbuf; } int readCirclebuf(struct Circlebuf *circlebuf) { int value = 0; value = circlebuf->buf[circlebuf->read]; circlebuf->buf[circlebuf->read] = 0; circlebuf->read = (circlebuf->read + 1) % Maxbuf; return value; } void OutCirclebuf(struct Circlebuf *circlebuf) { int i; printf("+++++緩沖區各單元的值.\n"); for (i = 0; i <Maxbuf; i++) printf("%d ", circlebuf->buf[i]); printf("\n"); } void sigend(int sig) { exit(0); } void *productThread(void *i) { int *n = (int *)i; int t = TimesOfOp; while (t--) { sem_wait(&empty);// sem_wait(&mutex);// writeCirclebuf(&circlebuf, n); printf("----------------生產者%d 寫入緩沖區的值%d \n", *n, *n); OutCirclebuf(&circlebuf); sem_post(&mutex); sem_post(&full); } } void *consumerThread(void *i) { int *n = (int *)i; int value = 0; int t = TimesOfOp; while (t--) { sem_wait(&full); sem_wait(&mutex); value = readCirclebuf(&circlebuf); printf("----------------消費者%d 取走產品的值%d \n",*n,value); OutCirclebuf(&circlebuf); sem_post(&mutex); sem_post(&empty); } } main() { int i; int ConsNum = 0, ProdNum = 0, ret; pthread_t cpid, ppid;// sem_init(&mutex, 0, 1); sem_init(&empty, 0, Maxbuf); sem_init(&full, 0, 0); signal(SIGINT, sigend); signal(SIGTERM, sigend); circlebuf.read = circlebuf.write = 0; for ( i = 0; i < Maxbuf; i++) circlebuf.buf[i] = 0; printf("請輸入生產者的數目 :"); scanf("%d",&ProdNum); int *pro=(int*)malloc(ProdNum*sizeof(int)); printf("請輸入消費者的數目 :"); scanf("%d", &ConsNum); int *con = (int *)malloc(ConsNum * sizeof(int)); for ( i = 1; i <= ConsNum; i++) { cpid = i; con[i - 1] = i; ret = pthread_create(&cpid, NULL, consumerThread,(void*)&con[i-1] ); if (ret != 0) { printf("Create thread error"); exit(1); } } for (i = 1; i <= ProdNum; i++) { ppid = i + 100; pro[i - 1] = i; ret = pthread_create(&ppid, NULL, productThread, (void *)&pro[i - 1]); if (ret != 0) { printf("Create thread error"); exit(1); } } sleep(1); sem_destroy(&mutex);// sem_destroy(&empty);// sem_destroy(&full);// pthread_exit(NULL);// }