第十周学习笔记

第12章   块设备I/O和缓冲区管理

一、主要内容

1.块设备I/O缓冲区

与内存访问相比,磁盘I/O速度较慢,所以不希望在每次执行读写文件操作时都执行磁盘I/O。因此,大多数文件系统使用I/O缓冲来减少进出存储设备的物理I/O数量

I/O缓冲的基本原理:

  • 文件系统使用一系列I/O缓冲区作为块设备的缓存内存。
  • 当进程试图读取(dev, blk)标识的磁盘块时,它首先在缓冲区缓存中搜索分配给磁盘块的缓冲区。
  • 如果该缓冲区存在并且包含有效数据,那么它只需从缓冲区中读取数据,而无须再次从磁盘中读取数据块。
  • 如果该缓冲区不存在,它会为磁盘块分配一个缓冲区,将数据从磁盘读入缓冲区,然后从缓冲区读取数据,当某个块被读入时,该缓冲区将被保存在缓冲区缓存中,以供任意进程对同一个块的下一次读/写请求使用。
  • 当进程写入磁盘块时,它首先会获取一个分配给该块的缓冲区。然后,它将数据写入缓冲区,将缓冲区标记为脏,以延迟写入,并将其释放到缓冲区缓存中 由于脏缓冲区包含有效的数据,因此可以使用它来满足对同一块的后续读/写清求,而不会引起实际磁盘I/O,脏缓冲区只有在被重新分配到不同的块时才会写入磁盘。

物理块设备I/O :每个设备都有一个I/O队列,其中包含等待I/O操作的缓冲区。

2.Unix I/O缓冲区

Unix缓冲区管理子系统由以下几部分组成

(1)I/O缓冲区

      内核中的一系列NBUF缓冲区用作缓冲区缓存。每个缓冲区用一个结构体表示。缓冲区结构体由两部分组成:用于缓冲区管理的缓冲头部分和用于数据块的数据部分。

(2)设备表

      每个块设备用一个设备表结构表示.每个设备表都有一个dev_list,包含当前分配给该设备的I/O缓冲区,还有一个io_ queue,包含设备上等待I/O操作的缓冲区。I/O队列的组织方式应确保最佳I/O操作。

(3)缓冲区初始化

当系统启动时,所有I/O缓冲区都在空闲列表中,所有设备列表和I/O队列均为空。

(4)缓冲区列表

当缓冲区分配给(dev, blk)时,它会被插入设备表的dev_list中.

(5)getblk/brelse 算法

getblk和brelse构成了Unix缓冲区管理方案的核心

3.Unix算法的优缺点

优点:简洁
缺点:

  • 效率低下:该算法依赖于重试循环
  • 缓存效果不可预知
  • 可能会出现饥饿
  • 该算法使用只适用丁单处理器系统的休眠/唤醒操作

4.使用信号量的缓冲区管理算法

PV算法:


二、实践部分

include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#define N 100
#define true 1
#define producerNum  10
#define consumerNum  5
#define sleepTime 1000

typedef int semaphore;
typedef int item;
item buffer[N] = {0};
int in = 0;
int out = 0;
int proCount = 0;
semaphore mutex = 1, empty = N, full = 0, proCmutex = 1;

void * producer(void * a){
    while(true){
        while(proCmutex <= 0);
        proCmutex--;
        proCount++;
        printf("produce a product: ID %d, buffer location:%d\n",proCount,in);
        proCmutex++;

        while(empty <= 0){
            printf("buffer is full\n");
        }
        empty--;

        while(mutex <= 0);
        mutex--;

        buffer[in] = proCount;
        in = (in + 1) % N;

        mutex++;
        full++;
        sleep(sleepTime);
    }
}

void * consumer(void *b){
    while(true){
        while(full <= 0){
            printf("buffer is empty\n");
        }
        full--;

        while(mutex <= 0);
        mutex--;

        int nextc = buffer[out];
        buffer[out] = 0;//消费完将缓冲区设置为0

        out = (out + 1) % N;

        mutex++;
        empty++;

        printf("produce a product: ID %d, buffer location:%d\n", nextc,out);
        sleep(sleepTime);
    }
}

int main()
{
    pthread_t threadPool[producerNum+consumerNum];
    int i;
    for(i = 0; i < producerNum; i++){
        pthread_t temp;
        if(pthread_create(&temp, NULL, producer, NULL) == -1){
            printf("ERROR, fail to create producer%d\n", i);
            exit(1);
        }
        threadPool[i] = temp;
    }//创建生产者进程放入线程池


    for(i = 0; i < consumerNum; i++){
        pthread_t temp;
        if(pthread_create(&temp, NULL, consumer, NULL) == -1){
            printf("ERROR, fail to create consumer%d\n", i);
            exit(1);
        }
        threadPool[i+producerNum] = temp;
    }//创建消费者进程放入线程池


    void * result;
    for(i = 0; i < producerNum+consumerNum; i++){
        if(pthread_join(threadPool[i], &result) == -1){
            printf("fail to recollect\n");
            exit(1);
        }
    }//运行线程池
    return 0;
}

 

 

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <errno.h>
#define total 20
sem_t remain, apple, pear, mutex;
static unsigned int vremain = 20, vapple = 0, vpear = 0;
void *father(void *);
void *mather(void *);
void *son(void *);
void *daughter(void *);
void print_sem();
int main()
{  
    pthread_t fa, ma, so, da;  
    sem_init(&remain, 0, total);//总数初始化为20 
    sem_init(&apple, 0, 0);//盆子中苹果数, 开始为0  
    sem_init(&pear, 0, 0);//盆子中梨子数, 开始为0   
    sem_init(&mutex, 0, 1);//互斥锁, 初始为1 
    pthread_create(&fa, NULL, &father, NULL);  
    pthread_create(&ma, NULL, &mather, NULL);  
    pthread_create(&so, NULL, &son, NULL); 
    pthread_create(&da, NULL, &daughter, NULL);    
    for(;;);
}
void *father(void *arg)
{  
    while(1)
    {      
        sem_wait(&remain);     
        sem_wait(&mutex);      
        printf("before A: remain=%u, apple_num=%u\n", vremain--, vapple++);
        printf("after A: remain=%u, apple_num%u\n", vremain, vapple);
        sem_post(&mutex);      
        sem_post(&apple);  
        sleep(1);  
    }
}
void *mather(void *arg)
{  
    while(1)
    {      
        sem_wait(&remain);     
        sem_wait(&mutex);      
        printf("before B: remain=%u, pear_num=%u\n", vremain--, vpear++);
        printf("after B: remain=%u, pear_num%u\n", vremain, vpear);
        sem_post(&mutex);  
        sem_post(&pear);   
        sleep(2);  
    }
}
void *son(void *arg)
{  
    while(1)
    {      
        sem_wait(&pear);   
        sem_wait(&mutex);   
        printf("before C: remain=%u, pear_num=%u\n", vremain++, vpear--);
        printf("after C: remain=%u, pear_num=%u\n", vremain, vpear);
        sem_post(&mutex);  
        sem_post(&remain);     
        sleep(3);
    }
}
void *daughter(void *arg)
{  
    while(1)
    {  
        sem_wait(&apple);  
        sem_wait(&mutex);
        printf("before D remain=%u, apple_num=%u\n", vremain++, vapple--);
        printf("after D: remain=%u, apple_num=%u\n", vremain, vapple);   
        sem_post(&mutex);  
        sem_post(&remain); 
        sleep(3);  
    }
}
void print_sem()
{  
    int val1, val2, val3;
    sem_getvalue(&remain, &val1);  
    sem_getvalue(&apple, &val2);   
    sem_getvalue(&pear, &val3);
    printf("Semaphore: remain:%d, apple:%d, pear:%d\n", val1, val2, val3);
}

 

posted @ 2022-11-05 15:00  20201320石志涛  阅读(18)  评论(0编辑  收藏  举报