第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); }
标签:apple,第十,void,笔记,学习,remain,mutex,缓冲区,sem From: https://www.cnblogs.com/sztsao/p/16773520.html