任务详情:自学教材第5章,提交学习笔记
Part1 知识点归纳&GPT提问
知识点归纳
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算法:
GPT提问
块设备I/O缓冲区
Unix I/O缓冲区管理算法
Part2 问题与解决思路
问题
自学的时候不太了解PV算法,搞不懂是干嘛的
GPT解决
最终解决方案
PV两个字母是荷兰文 Passeren(通过),Vrijgeven(释放)的简称。PV操作与信号量的处理相关,P表示通过的意思,V表示释放的意思。所谓信号量,实际上就是用来控制进程状态的一个代表某一资源的存储单元。例如,P1和P2是分别将数据送入缓冲B和从缓冲B读出数据的两个进程,为了防止这两个进程并发时产生错误,狄克斯特拉设计了一种同步机制叫“PV操作”,P操作和V操作是执行时不被打断的两个操作系统原语。执行P操作P(S)时信号量S的值减1,若结果不为负则P(S)执行完毕,否则执行P操作的进程暂停以等待释放。执行V 操作V(S)时,S的值加1,若结果不大于0则释放一个因执行P(S)而等待的进程。对P1和P2可定义两个信号量S1和S2,初值分别为1和0。进程P1在向缓冲B送入数据前执行P操作P(S1),在送入数据后执行V操作V(S2)。进程P2在从缓冲B读取数据前先执行P操作P(S2),在读出数据后执行V操作V(S1)。当P1往缓冲B送入一数据后信号量S1之值变为0,在该数据读出后S1之值才又变为1,因此在前一数未读出前后一数不会送入,从而保证了P1和P2之间的同步。PV操作属于进程的低级通信。
P、V原语的具体操作如下:
P(S)将信号量S的值减1,即S=S-1;如果S≥0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
V(S)将信号量S的值加1,即S=S+1;如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
还有一个比较易混淆的东西就是互斥和同步,那么他们两个又有什么区别?
互斥:(一般来说是两个进程间或进程内对同一资源(会访问临界资源),不能同时进行,就用互斥)
⑴每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。
⑵P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。
⑶互斥信号量的初值一般为1。
同步:(两个进程间,可以同时进行,但有共享资源,两者需要竞争(需要等待,必须有个执行先后顺序)就用同步,其实就是基本思想,所以说互斥就特殊的同步)
(1)、同步信号量一般不出现在同一进程中。
(2)、同步的P操作应出现在互斥的P操作前。
Part3 实践过程截图
实践1:运行以下代码
Pv.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include "sem_com.c"
#define DELAY_TIME 3
int main() {
pid_t pid;
int sem_id;
key_t sem_key;
sem_key=ftok(".",'a');
sem_id=semget(sem_key,1,0666|IPC_CREAT);
init_sem(sem_id,1);
if ((pid=fork())<0) {
perror("Fork error!\n");
exit(1);
} else if (pid==0) {
sem_p(sem_id);
printf("Child running...\n");
sleep(DELAY_TIME);
printf("Child %d,returned value:%d.\n",getpid(),pid);
sem_v(sem_id);
exit(0);
} else {
sem_p(sem_id);
printf("Parent running!\n");
sleep(DELAY_TIME);
printf("Parent %d,returned value:%d.\n",getpid(),pid);
sem_v(sem_id);
waitpid(pid,0,0);
del_sem(sem_id);
exit(0);
}
}
sem_com.c
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
int init_sem(int sem_id,int init_value) {
union semun sem_union;
sem_union.val=init_value;
if (semctl(sem_id,0,SETVAL,sem_union)==-1) {
perror("Sem init");
exit(1);
}
return 0;
}
int del_sem(int sem_id) {
union semun sem_union;
if (semctl(sem_id,0,IPC_RMID,sem_union)==-1) {
perror("Sem delete");
exit(1);
}
return 0;
}
int sem_p(int sem_id) {
struct sembuf sem_buf;
sem_buf.sem_num=0;
sem_buf.sem_op=-1;
sem_buf.sem_flg=SEM_UNDO;
if (semop(sem_id,&sem_buf,1)==-1) {
perror("Sem P operation");
exit(1);
}
return 0;
}
int sem_v(int sem_id) {
struct sembuf sem_buf;
sem_buf.sem_num=0;
sem_buf.sem_op=1;
sem_buf.sem_flg=SEM_UNDO;
if (semop(sem_id,&sem_buf,1)==-1) {
perror("Sem V operation");
exit(1);
}
return 0;
}
运行结果:
Part4 其他
学习感想:自学完这一章最大的感悟是要学会进行联想,当遇到不懂的知识的时候,要学会把别的科目的知识拿出来辅助理解。再一个就是脑子要灵活,操作系统也学了很久了,以前一直没把这两门课联系在一起,现在想想Linux学起来不过也就是一个操作系统罢了,虽然和Windows不一样,但是抽象起来都是一个模式,以前学的进程和线程、同步等知识在操作系统课上都学过,只是一直没有意识把两门课放到一起学。在以后我还要多多培养这方面的能力,学一门课有不止一门课的收获,做到事半功倍。
标签:10,int,信息安全,笔记,信号量,缓冲区,sem,buf,id From: https://www.cnblogs.com/wjmbk123/p/17840770.html