操作系統實驗七之有限緩衝問題

一、實驗描述

  利用有限緩衝問題的解決思想,實現生產者消費者問題,主要利用線程同步機制完成。使用三個信號量: empty (以記錄有多少空位)、full (以記錄有多少滿位)以及mutex (二進制信號量或互斥信號量,以保護對緩衝插入與刪除的操作)。對於本項目, empty 與full 將採用標準計數信號量,而mutex 將採用二進制信號量。生產者與消費者作爲獨立線程,在empty、full、mutex 的同步前提下,對緩衝進行插入與刪除。

二、實驗測試樣例

  測試數據文件包括n行測試數據,分別描述創建的n個線程是生產者還是消費者,以及生產者或消費者存放或取產品的開始時間和持續時間。每行測試數據包括四個字段,各個字段間用空格分隔。第一字段爲一個正整數,表示線程序號。第二字段表示相應線程角色,P表示生產者,C表示消費者。第三字段爲一個正數,表示存放或取出操作的開始時間:線程創建後,延遲相應時間(單位爲秒)後發出對共享資源的使用申請。第四字段爲一個正數,表示操作的持續時間。第五字段爲一個正數(僅生產者有),表示生產的產品號。當線程申請成功後,開始對共享資源的操作,該操作持續相應時間後結束,並釋放共享資源。例如:


1 C 3 5
2 P 4 5 1
3 C 5 2
4 C 6 5
5 P 7 3 2
6 P 8 4 3


三、知識準備

  Linux POSIX線程互斥和同步相關知識。
  
|:mutex初始化
線程的互斥量mutex數據類型是pthread_mutex_t。 使用前要對它進行初始化,有兩種方法:
(1)靜態分配的互斥量的初始化:

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

(2)動態分配的互斥量的初始化:

首先申請內存(malloc),
再用pthread_mutex_init進行初始化。
釋放時,必須先調用pthread_mutex_destroy,而後再釋放內存(free)。

例如:

//創建10個線程計算0~9的和。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#define THREAD_NUMBER 10

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

int sum =0;

void* inc(void *arg) //線程執行的函數
{
   int i =(*(int *)arg); 
   pthread_mutex_lock(&mutex);
   sum = sum +i; 
   pthread_mutex_unlock(&mutex);
   return NULL;
}

int main(int argc, char *argv[])
{
   pthread_t pt[THREAD_NUMBER];
   int i;
   int arg[THREAD_NUMBER];    
   for(i=0; i<THREAD_NUMBER; i++) {
       arg[i]=i;    
       if(pthread_create(&pt[i], NULL, inc, (void *)&arg[i])!=0){
          printf("pthread_create error\n");
          exit(1);
       }       
   }
   for(i=0; i<THREAD_NUMBER; i++)
       if(pthread_join(pt[i],NULL)!=0){
          printf("pthread_join error\n");
          exit(1);
       }
   printf("sum is %d\n",sum);
   pthread_mutex_destroy(&mutex);
   return 0;
}

|:POSIX 信號量
  POSIX 信號量在多線程編程中可以起到同步或互斥的作用。用POSIX 信號量可以實現傳統操作系統P、V操作(即對應課本的wait、signal)。
  由於POSIX信號量不是內核負責維護,所以當進程退出後,POSIX信號量自動消亡。

#include <semaphore.h>
//定義信號量
sem_t  sem;
//創建信號量
int sem_init(sem_t *sem, int pshared, unsigned int value);
//相當於wait操作,即申請資源。
int sem_wait(sem_t * sem);
//是函數sem_wait()的非阻塞版本。若信號量大於0,它直接將信號量sem的值減一併返回0;否則,它立即返回錯誤類型EAGAIN。
int sem_trywait(sem_t * sem);
//相當於signal操作,釋放資源
int sem_post(sem_t * sem);
//獲得信號量當前值
int sem_getvalue(sem_t * sem, int * sval);
//用來釋放信號量
int sem_destroy(sem_t * sem);

四、代碼實現

buffer.h

#ifndef BUFFER_H_
#define BUFFER_H_

#include <iostream>
#define BUFFER_SIZE 5
using namespace std;

typedef int buffer_item;

struct Buffer{
    Buffer(){
        count = 0;
        front = 0;
        rear = 0;
        for(int i = 0; i < BUFFER_SIZE; i++){
            items[i] = 0;
        }
    }
    buffer_item items[BUFFER_SIZE];
    int count;
    int front;
    int rear;
};

int insert_item(buffer_item item);

int remove_item();

#endif

buffer.cpp

#include "buffer.h"

Buffer *buffer = new Buffer();
int insert_item(buffer_item item){
    if(buffer->count < BUFFER_SIZE){
        buffer->items[buffer->rear] = item;
        cout << "Product: " << buffer->items[buffer->rear] << endl;
        buffer->count++;
        buffer->rear++;
        if(buffer->rear % BUFFER_SIZE == 0) buffer->rear = 0;
        return 0;
    }

    return -1;
}

int remove_item(){
    if(buffer->count > 0){
        cout<< "Consume: " << buffer->items[buffer->front] << endl;
        buffer->items[buffer->front] = 0;
        buffer->count--;
        buffer->front++;
        if(buffer->front % BUFFER_SIZE == 0) buffer->front = 0;
        return 0;
    }

    return -1;
}

deal.h

#ifndef DEAL_H_
#define DEAL_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdlib>
#include <iostream>
using namespace std;

typedef struct Data{
    Data(){
        serial_num = 0;
        character = ' ';
        start = 0;
        last = 0;
        product = 0;
    }

    int serial_num;
    char character;
    int start;
    int last;
    int product;
} Instruction;

Instruction *Deal(char file[]);

#endif

deal.cpp

#include "deal.h"

Instruction *Deal(char file[]){
    Instruction *ins = new Data();
    int i;
    int j = 0;
    string tmp = "";

    int len = strlen(file);
    for(i = 0; i < len; i++){
        if(file[i] != ' ' && file[i] != '\n')
            tmp += file[i];

        else{
            if(tmp != ""){
                switch(j){
                    case 0: ins->serial_num = atoi(tmp.c_str());
                            tmp = "";
                            break;
                    case 1: ins->character = tmp.at(0);
                            tmp = "";
                            break;
                    case 2: ins->start = atoi(tmp.c_str());
                            tmp = "";
                        break;
                    case 3: ins->last = atoi(tmp.c_str());
                            tmp = "";
                        break;
                    case 4: ins->product = atoi(tmp.c_str());
                            tmp = "";
                            break;
                }
                j++;
            }
        }
    }
    return ins;
}

Main.cpp

#include <pthread.h>
#include <sys/types.h>
#include <semaphore.h>
#include <unistd.h>
#include "buffer.h"
#include "deal.h"
#define MAX 20

struct sto{
    sem_t mutex;
    sem_t nempty;
    sem_t nstored;
};
struct sto shared;

void *produce(void *arg)
{
    Instruction *ins = (Instruction*)arg;
    sem_wait(&shared.nempty);
    sem_wait(&shared.mutex);
    sleep(ins->start);
    insert_item(ins->product);
    sleep(ins->last);
    sem_post(&shared.mutex);
    sem_post(&shared.nstored);
    return(NULL);
}

void *consume(void *arg)
{
    Instruction *ins = (Instruction*)arg;
    sem_wait(&shared.nstored);
    sem_wait(&shared.mutex);
    sleep(ins->start);
    remove_item();
    sleep(ins->last);
    sem_post(&shared.mutex);
    sem_post(&shared.nempty);

    return(NULL);
}

int main()
{
    FILE *fp;
    char file[MAX];
    int i;

    pthread_t tid_produce;
    pthread_t tid_consumer;
    Instruction *ins = new Data();
    sem_init(&shared.mutex, 0, 1);
    sem_init(&shared.nempty, 0, 5);
    sem_init(&shared.nstored, 0, 0);

    fp = fopen("test.txt", "r");
    while(fgets(file, MAX, fp)){
        ins = Deal(file);
        if(ins->character == 'P'){
            pthread_create(&tid_produce, NULL, produce, (void*)ins);
        }
        else{
            pthread_create(&tid_consumer, NULL, consume, (void*)ins);
        }
        /*cout<<ins->serial_num<<" "<<ins->character<<" ";
        cout<<ins->start<<" "<<ins->last<<" ";
        cout<<ins->product<<endl;*/

    }

    sem_destroy(&shared.mutex);
    sem_destroy(&shared.nempty);
    sem_destroy(&shared.nstored);

    sleep(60);

    return 0;
}

Makefile

CC = g++
objects = Main.o buffer.o deal.o

Main: $(objects)
    $(CC) -o Main $(objects) -pthread
Main.o: Main.cpp
buffer.o: buffer.h
deal.o: deal.h
.PHONY: clean
clean:
    -rm Main $(objects)

五、實驗結果

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章