哈工大操作系統實驗(四)進程同步

本次實驗比較簡單,相較于前幾屆需要在linux0.11 底下實現信號量,這次只需要在linux下寫個利用信號量解決生產者消費者問題已經很簡單了.
實驗要求:
在Ubuntu上編寫應用程序“pc.c”,解決經典的生產者—消費者問題,完成下面的功能:

  1. 建立一個生產者進程,N個消費者進程(N>1);
  2. 用文件建立一個共享緩沖區;
  3. 生產者進程依次向緩沖區寫入整數0,1,2,...,M,M>=500;
  4. 消費者進程從緩沖區讀數,每次讀一個,并將讀出的數字從緩沖區刪除,然后將本進程ID和數字輸出到標準輸出;
    緩沖區同時最多只能保存10個數。

要求用信號量來解決問題:
pc.c中將會用到sem_open()、sem_close()、sem_wait()和sem_post()等信號量相關的系統調用

要用到的函數說明:

int fseek(FILE *stream, long offset, int fromwhere);
函數設置文件指針stream的位置。
如果執行成功,stream將指向以fromwhere為基準,偏移offset(指針偏移量)個字節的位置,函數返回0。
如果執行失敗(比如offset超過文件自身大小),則不改變stream指向的位置,函數返回一個非0值。
size_t fread(void *buffer,size_t size,size_t count, FILE *stream );   
buffer   是讀取的數據存放的內存的指針   
size     是每次讀取的字節數   
count    是讀取次數   
stream   是要讀取的文件的指針 
從一個文件流中讀數據,最多讀取count個元素,每個元素size字節,如果調用成功返回實際讀取到的元素個數,如果不成功或讀到文件末尾返回 0。
size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
(1)buffer:是一個指針,對fwrite來說,是要獲取數據的地址;
(2)size:要寫入內容的單字節數;
(3)count:要進行寫入size字節的數據項的個數;
(4)stream:目標文件指針;
(5)返回實際寫入的數據項個數count。

思路:建立文件緩沖區
0-9位存生產的數據,第10位存儲當前讀到的位置.

消費者讀取的位置的時候要執行兩次,一次讀出當前所讀位置,第二次根據此位置計算位偏移;


fseek( fp, 10*sizeof(int), SEEK_SET );
fread( &Outpos, sizeof(int), 1, fp);

fseek( fp, Outpos*sizeof(int), SEEK_SET );
fread( &costnum, sizeof(int), 1, fp);

下面是實驗所需文件pc.c:

#define   __LIBRARY__
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>

#define ALLNUM 550
#define CUSTOMERNUM 5
#define BUFFERSIZE 10
void Producters(pid_t pid,FILE *fp);
void Customer(pid_t pid,FILE *fp);
sem_t *empty,*full,*mutex;
FILE *fp=NULL;
int Inpos=0;
int Outpos=0;


int main()
{
    int i,j,k;
    pid_t producter;
    pid_t customer;
    empty=(sem_t *)sem_open("empty",O_CREAT,0064,10);
    full=(sem_t *)sem_open("full",O_CREAT,0064,0);
    mutex=(sem_t*)sem_open("mutex",O_CREAT,0064,1);

//開啟三個信號量
    fp=fopen("products.txt","wb+");
    fseek(fp,10*sizeof(int),SEEK_SET);
    fwrite(&Outpos,sizeof(int),1,fp);
    fflush(fp);
    producter=fork();
    if(producter==0)
    {
        Producters(producter,fp);
    }
    for (i=0;i<CUSTOMERNUM;i++)
    {

        customer=fork();
        if(customer==0)
        {
            Customer(customer,fp);
        }
    }
    wait(NULL);
    wait(NULL);
    wait(NULL);
    wait(NULL);
    wait(NULL);
    wait(NULL);
    //開了6個進程
    sem_unlink("empty");
    sem_unlink("full");
    sem_unlink("mutex");
    fclose(fp);
    return 0;
}
void Producters(pid_t pid,FILE *fp)
{
    int i=0;
    for (i=0;i<ALLNUM;i++)
    {
        sem_wait(empty);
        sem_wait(mutex);
        fseek( fp, Inpos * sizeof(int), SEEK_SET );
        fwrite(&i,sizeof(int),1,fp);
        fflush(fp);
        Inpos=(Inpos +1) % BUFFERSIZE;
        sem_post(mutex);
        sem_post(full);
    }
     return;
}

void Customer(pid_t pid,FILE *fp)
{
    int j,productid;
    for (j=0;j<ALLNUM/CUSTOMERNUM;j++)
    {
        sem_wait(full);
        sem_wait(mutex);
        fflush(stdout);
        fseek(fp,10*sizeof(int),SEEK_SET);
        fread(&Outpos,sizeof(int),1,fp);
        fseek(fp,Outpos*sizeof(int),SEEK_SET);
        fread(&productid,sizeof(int),1,fp);
        printf("%d:   %d\n",getpid(),productid);
        fflush(stdout);
        Outpos=(Outpos+1)% BUFFERSIZE;
        fseek(fp,10*sizeof(int),SEEK_SET);
        fwrite(&Outpos,sizeof(int),1,fp);
        fflush(fp);
        sem_post(mutex);
        sem_post(empty);
    }
    return;
}



報告:
(1)在pc.c中去掉所有與信號量有關的代碼,再運行程序,執行效果有變化嗎?為什么會這樣?
執行結果Customer的消費數據沒有按遞增的順序輸出,而且且fread()函數將產生錯誤;
原因:
因為沒有信號量P(S)控制,導致生產者可能在緩沖區滿后繼續生產,導致沒有被消費的數據被覆蓋,使得消費者消費的數據不是遞增序列。
同時,沒有信號量V(S)控制,導致消費者可能在讀取所有數據后仍然繼續讀取,導致讀取的數據無效。
沒有mutex信號量控制導致出現多進程并發訪問緩沖區,導致出現fread()錯誤。
(2)實驗的設計者在第一次編寫生產者——消費者程序的時候,是這么做的:
Producer()
{ P(Mutex); //互斥信號量
生產一個產品item;
P(Empty); //空閑緩存資源
將item放到空閑緩存中;
V(Full); //產品資源
V(Mutex);
}
Consumer()
{ P(Mutex);
P(Full);
從緩存區取出一個賦值給item;
V(Empty);
消費產品item;
V(Mutex);
}
這樣可行嗎?如果可行,那么它和標準解法在執行效果上會有什么不同?如果不可行,那么它有什么問題使它不可行?

這樣做不可行,只有當緩沖區可寫或者可讀時,才能鎖定該臨界資源,否則容易出現緩沖區未鎖定(mutex=1),consumer鎖定該緩沖區,卻發現empty=10,full=0,等待緩沖區有字符信號量,這樣程序會進入死鎖狀態。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容