首页 > 其他分享 >20201317 LYX 第12章 块设备I/O和缓冲区管理

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

时间:2022-11-02 19:45:19浏览次数:61  
标签:12 void LYX 信号量 include 缓冲区 sem NULL 20201317

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

知识总结

  1. 解释块设备I/O的原理和I/O缓冲的优点
  2. 介绍Unix的缓冲区管理算法
  3. 利用信号量设计新的缓冲区管理算法,以提高I/O缓冲区的缓存效率和性能
  4. 介绍简单的PV算法及其特点

基本概念
读写普通文件的算法依赖于两个关键操作,即get_block和put_block,这两个操作将磁盘块读写到内存缓冲区中。由于与内存访问相比,磁盘I/O速度较慢,所以不希望在每次执行读写文件操作时都执行磁盘I/O。因此、大多数文件系统使用I/O缓冲来减少进出存储设备的物理I/O数量。

合理设计的I/O缓冲方案可显著提高文件I/O效率并增加系统吞吐量。

I/O缓冲的基本原理非常简单。文件系统使用系列I/O缓冲区作为块设备的缓存内存。当进程试图读取(dev,blk)标识的磁盘块时。它首先在缓冲区缓存中搜索分配给磁盘块的缓冲区。

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

在read file/write file中,我们假设它们从内存中的一个专用缓冲区进行读/写。
对于I/O缓冲,将从缓冲区缓存中动态分配缓冲区。假设BUFFER是缓冲区的结构类型,而且getblk(dev,blk)从缓冲区缓存中分配一个指定给(dev,blk)的缓冲区。定义一个bread(dev,blk)函数,它会返回一个包含有效数据的缓冲区(指针)。

从缓冲区读取数据后,进程通过brelse(bp)将缓冲区释放会缓冲区缓存。同理,定义一个write_block(dev, blk, data)函数。

同步写入操作等待写操作完成,用于顺序块或可移动块设备。

当I/O操作完成后,设备中断处理程序会完成当前缓冲去上的I/O操作,并启动I/O队列中下一个缓冲区的I/O。

Unix I/O缓冲区管理算法

实践过程

  1. 信号同步

    生产者消费者问题

    “生产者—消费者”问题 (producer/consumer problem) 是最著名的进程同步问题。
    该问题描述了共享固定大小缓冲区的两个线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。
    与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

    它是许多相互合作进程的抽象,如输入进程与计算进程;计算进程与打印进程等。

    要解决该问题,就必须让生产者在缓冲区满时休眠,等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。

    设置两个资源信号量及一个互斥信号量。
    资源信号量 empty:说明空缓冲区的数目,其初值为有界缓冲池的大小n。
    资源信号量 full:说明满缓冲区的数目(即产品数目),其初值为 0。full+ empty= n。
    互斥信号量 s: 说明该有界缓冲池是一个临界资源,必须互斥使用,其初值为 1。

    //生产者消费者问题
    #include<stdio.h>
    #include<unistd.h>
    #include<semaphore.h>
    #include<pthread.h>
    sem_t empty,full,s;
    int buffer[10]={-1};
    int fill=0;
    int use=0;
    void put(int value){
    	buffer[fill]=value;
    	fill=(fill+1)%11;
    }
    int get(){
    	int tmp=buffer[use];
    	use=(use+1)%11;
    	return tmp;
    }
    void *producer(void *arg){
    	printf("producer\n");
    
    	int i=0;
    	for(i=0;i<=20;i++){
    		//sleep(3);
    		sem_wait(&empty);
    		sem_wait(&s);
    		
    		put(i);
    		sem_post(&s);
    		sem_post(&full);
    		printf("producer put:%d\n",i);
    	}
    
    	//pthread_exit(0);
    }
    void *consumer(void *arg){
    	printf("consumer\n");
    	
    	int i=0;
    	for(i=0;i<=20;i++){
    		//sleep(3);
    		sem_wait(&full);
    		sem_wait(&s);
    		
    		int tmp=get();
    		
    		sem_post(&s);
    		sem_post(&empty);
    		printf("consumer get:%d\n",tmp);
    	}
    	//pthread_exit(0);
    }
    int main(int argv,char * args[]){
    	sem_init(&empty,0,10);
    	sem_init(&full,0,0);
    	sem_init(&s,0,1);
    	pthread_t pro,con;
    	pthread_create(&pro,NULL,producer,NULL);
    	pthread_create(&con,NULL,consumer,NULL);
    	pthread_join(con,NULL);
    	pthread_join(pro,NULL);
    	
    	
    
    }
    

    image-20221102192010352

  2. 吃水果问题

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>

//定义信号量
//盘子空信号量
sem_t empty;//初始值为1,表示当前盘子为空
//苹果信号量
sem_t apple;//初始值为0,表示当前盘子没有苹果
//橘子信号量
sem_t orange;//初始值为0,表示当前盘子没有橘子
//函数声明
void* father(void* arg);//父亲线程执行函数
void* mother(void* arg);//母亲线程执行函数
void* son(void* arg);//儿子线程执行函数
void* daughter(void* arg);//女儿线程执行函数

void* father(void* arg) {
while(1) {
sem_wait(&empty);
// 放入一个苹果
printf("father --> apple\n");
sem_post(&apple);
        sleep(rand() % 10); // 随机休眠一段时间
    }
}
void* mother(void* arg)
{
	while(1)
	{
		sem_wait(&empty);
		//放入一个橘子
		printf("mother --> orange\n");
		sem_post(&orange);
		sleep(rand() % 10); // 随机休眠一段时间
	}
}
void* son(void* arg)
{
	while(1)
	{   //等盘子不为空才开始执行下面的,盘子不为空说明有橘子或者苹果
        sem_wait(&apple);//当苹果为1时,做减法,0则不做
		printf("son --> apple\n");
		//把盘子信号量释放,表示盘子为空,信号量加1
		sem_post(&empty);
        sleep(rand() % 10); // 随机休眠一段时间
		}
}
void* daughter(void* arg)
{
	while(1)
	{   //等盘子不为空才开始执行下面的,盘子不为空说明有橘子或者苹果
        sem_wait(&orange);//当橘子为1时,做减法,0则不做
		printf("daughter --> orange\n");
		//把盘子信号量释放,表示盘子为空,信号量加1
		sem_post(&empty);
        sleep(rand() % 10); // 随机休眠一段时间
		}
}
int main()
{   //定义父亲,母亲,儿子,女儿线程
	pthread_t fatherThread,motherThread,sonThread,daughterThread;
	//初始化信号量,empty 1,orange 0,apple 0;
	sem_init(&empty,0,1);
	sem_init(&orange,0,0);
	sem_init(&apple,0,0);
	//创建线程
	pthread_create(&fatherThread, NULL, father, NULL);
	pthread_create(&motherThread, NULL, mother, NULL);
	pthread_create(&sonThread, NULL, son, NULL);
	pthread_create(&daughterThread, NULL, daughter, NULL);
	pthread_join(fatherThread, NULL);
    pthread_join(motherThread, NULL);
	pthread_join(sonThread, NULL);
	pthread_join(daughterThread, NULL);
	
}

image-20221102192322918

  1. setbuf()和setvbuf()函数的实际意义在于:用户打开一个文件后,可以建立自己的文件缓冲区,而不必使用fopen()函数打开文件时设定的默认缓冲区。这样就可以让用户自己来控制缓冲区,包括改变缓冲区大小、定时刷新缓冲区、改变缓冲区类型、删除流中默认的缓冲区、为不带缓冲区的流开辟缓冲区等。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
   char buff[1024];

   memset( buff, '\0', sizeof( buff ));
 
   fprintf(stdout, "启用全缓冲\n");
   setvbuf(stdout, buff, _IOFBF, 1024);
 
   fprintf(stdout, "这里是 runoob.com\n");
   fprintf(stdout, "该输出将保存到 buff\n");
   fflush( stdout );
 
   fprintf(stdout, "这将在编程时出现\n");
   fprintf(stdout, "最后休眠五秒钟\n");
 
   sleep(5);
 
   return(0);
}

image-20221102192602599

标签:12,void,LYX,信号量,include,缓冲区,sem,NULL,20201317
From: https://www.cnblogs.com/lyxhhz/p/16852120.html

相关文章

  • CSP2020-12-T5
    星际旅行算法:线段树、离散化题意:你需要维护\(3\)维空间的\(n(1\leqn\leq10^9)\)个点,初始时这些点的三维坐标都是\(0\)。将有以下\(4\)种操作\(m(1\leqm\leq......
  • 第五章12
    【题目描述】有一只猴子,第一天摘了若干个桃子,当即吃了一半,但还觉得不过瘾,就又多吃了一个。第2天早上又将剩下的桃子吃掉一半,还是觉得不过瘾,就又多吃了两个。以后每天早......
  • SQLSERVER 2012迁移实施方案
    一、概述一台SQLSERVER2012企业版的数据库需要迁移到另一台机器上,具体情况如下:登陆账号众多,有数百个。job众多,有数百个。DB库的数量多,数据大,DB总大小达10T多,DB......
  • macOS Ventura 13系统与之前12系统不同之处的对比,你适应了没
    macOSVentura13系统升级后,发现跟macOS12Monterey的界面有很大的变化,有些设置找不到在哪里了,今天这篇文章跟大家讲讲macOSVentura13系统跟macOS12Monterey都有那些......
  • 力扣 129. 求根节点到叶节点数字之和
    129.求根节点到叶节点数字之和给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。每条从根节点到叶节点的路径都代表一个数字:例......
  • day12 --> (Web概念回顾、Tomcat服务器、Servlet入门)
    Web相关概念的回顾: 1.软件架构:1.B/S:浏览器/服务器端2.C/S:客户端/服务器端2.资源分类:1.静态资源:所有用户访问后,得到的结果都是一样的,称之为静态资源如:html、......
  • 【原子样式实践】第12篇 一次搞定微信开发者工具的原子样式扩展
    原子样式虽好,在IDE中使用,有扩展辅助就更好。本文介绍如何开发微信开发者工具的原子样式扩展,支持原子样式的自动生成,支持特色功能组合样式,支持特色功能样式使用统计报告。1......
  • SUSE12 SP4 FOR SA*P S4安装教程(一)
    众所周知,现在SA*P S4/HANA只支持SUSE系统环境了,所以从本文开始,打算用三篇文章介绍SUSE12、HANA2.0、SA*PS41909系统的安装过程。其实安装SUSE很简单,在SUSE官网https://ww......
  • SuSE 12 SP5配置静态IP地址
    平时比较常用CentOS系统,SuSE配置静态IP与之稍有不同,在这里做一下记录设置ip地址linux-38s9:/etc/sysconfig/network#catifcfg-eth0BOOTPROTO='static'BROADCAST=......
  • CF1208D Restore Permutation
    题目传送门思路别的题解讲的比较奇妙,来一篇易懂的题解。首先我们发现最后一个位置的值是可以首先确定的,因为它前面的数已经填完了。设最后一个位置的数为\(x\),则它的......