标签:字节 目录 mdi fork eof 进入 linux共享内存 last 内容
操作系统(Operating System,简称OS)是管理计算机硬件与软件资源的计算机程序。操作系统需要处理如管理与配置内存、决定系统资源供需的优先次序、控制输入设备与输出设备、操作网络与管理文件系统等基本事务。操作系统也提供一个让用户与系统交互的操作界面。
例题1在测量控制系统中,数据采集任务把所采集的数据送往一单缓冲区;计算任务从该单缓冲区中取出数据进行计算。试写出利用信号量机制实现两任务共享单缓冲区的同步算法。
Semaphore: empty=1,full=0 |
|
采集进程: While(1) P(empty) Put data V(full) |
计算进程: While(1) P(full) get data V(empty) |
进程 |
到达时刻 |
运行时间 |
优先级 |
P1 |
0 |
8 |
1 |
P2 |
2 |
12 |
4 |
P3 |
8 |
3 |
5 |
P4 |
9 |
7 |
3 |
解答:(1)非抢占式:P1,P3,P2,P4
进程 |
到达时刻 |
运行时间 |
优先级 |
开始运行 |
暂停运行 |
完成时间 |
周转时间 |
P1 |
0 |
8 |
1 |
0 |
8 |
8 |
|
P3 |
8 |
3 |
5 |
8 |
11 |
3 |
|
P2 |
2 |
12 |
4 |
11 |
23 |
21 |
|
P4 |
9 |
7 |
3 |
23 |
30 |
21 |
|
平均周转时间:=(8+3+21+21)/4=13.25 |
(2)抢占式:
进程 |
到达时刻 |
运行时间 |
优先级 |
开始/继续运行 |
暂停运行 |
剩余运行时间 |
完成时间 |
周转时间 |
P1 |
0 |
8 |
1 |
0 |
2 |
6 |
||
P2 |
2 |
12 |
4 |
2 |
8 |
6 |
||
P3 |
8 |
3 |
5 |
8 |
11 |
3 |
||
P2 |
11 |
17 |
15 |
|||||
P4 |
9 |
7 |
3 |
17 |
24 |
15 |
||
P1 |
24 |
30 |
30 |
|||||
平均周转时间:=(3+15+15+30)/4=15.75 |
例题3某时刻系统的A、B、C、D四种资源状态如下表所示:
Pno |
Allocation |
Max |
Available |
P0 |
0012 |
0112 |
1540 |
P1 |
1000 |
1750 |
|
P2 |
1354 |
2356 |
|
P3 |
0014 |
0656 |
(1)系统中四类资源各自的总数是多少?
(2)请写出Need矩阵。
(3)当前系统状态是否安全?请写出一个安全序列。
(4)如果P1发出请求(0,4,2,0),是否可以满足该请求?如果可以,请给出安全序列。
解答:(1) 系统中四类资源各自的总数是多少?
(3,8,11,10)
(2) 请写出Need矩阵。
Pno |
Need |
P0 |
0100 |
P1 |
0330 |
P2 |
1002 |
P3 |
0642 |
(3) 当前系统状态是否安全?请写出一个安全序列。
P0,P2,(P1,P3)
(4) 如果P1发出请求(0,4,2,0),是否可以满足该请求?如果可以,请给出安全序列。
P0,P2,(P1,P3)
(5) 请分析利用银行家算法解决死锁问题时的局限性。
银行家算法要求每个进程事先给出其所需要资源的最大数量,这在实际环境中不现实。
简答:0A5CH=(1010 0101 1100)2,页号为2,块号为4,则物理地址为:(01 0010 0101 1100)2,即125CH
103CH=(0001 0000 0011 1100)2,页号为4,缺页中断
1A5CH=(0001 1010 0101 1100)2,页号为6,越界中断解答:95%×2 + (2+10)×5%×99% + (2+10+107)×(1-95%)×(1-99%)
or
95%×2 + 5%×( 99%×(2+10) + 1%×(2+10+107))
采用FIFO算法:缺页次数:13次;
|
1 |
2 |
3 |
4 |
5 |
3 |
4 |
1 |
6 |
7 |
8 |
7 |
8 |
9 |
7 |
8 |
9 |
5 |
4 |
5 |
4 |
2 |
|
缺 |
缺 |
缺 |
缺 |
缺 |
|
|
缺 |
缺 |
缺 |
缺 |
|
|
缺 |
|
|
|
缺 |
缺 |
|
|
缺 |
|
1 |
1 |
1 |
1 |
5 |
|
|
5 |
5 |
5 |
8 |
|
|
8 |
|
|
|
8 |
8 |
|
|
2 |
|
|
2 |
2 |
2 |
2 |
|
|
1 |
1 |
1 |
1 |
|
|
9 |
|
|
|
9 |
9 |
|
|
9 |
|
|
|
3 |
3 |
3 |
|
|
3 |
6 |
6 |
6 |
|
|
6 |
|
|
|
5 |
5 |
|
|
5 |
|
|
|
|
4 |
4 |
|
|
4 |
4 |
7 |
7 |
|
|
7 |
|
|
|
7 |
4 |
|
|
4 |
换出 |
|
|
|
|
1 |
|
|
2 |
3 |
4 |
5 |
|
|
1 |
|
|
|
6 |
7 |
|
|
8 |
采用LRU算法:缺页次数:13次
|
1 |
2 |
3 |
4 |
5 |
3 |
4 |
1 |
6 |
7 |
8 |
7 |
8 |
9 |
7 |
8 |
9 |
5 |
4 |
5 |
4 |
2 |
|
缺 |
缺 |
缺 |
缺 |
缺 |
|
|
缺 |
缺 |
缺 |
缺 |
|
|
缺 |
|
|
|
缺 |
缺 |
|
|
缺 |
|
1 |
1 |
1 |
1 |
5 |
|
|
5 |
6 |
6 |
6 |
|
|
6 |
|
|
|
8 |
8 |
|
|
2 |
|
|
2 |
2 |
2 |
2 |
|
|
1 |
1 |
1 |
1 |
|
|
9 |
|
|
|
9 |
9 |
|
|
9 |
|
|
|
3 |
3 |
3 |
|
|
3 |
3 |
7 |
7 |
|
|
7 |
|
|
|
5 |
5 |
|
|
5 |
|
|
|
|
4 |
4 |
|
|
4 |
4 |
4 |
8 |
|
|
8 |
|
|
|
7 |
4 |
|
|
4 |
换出 |
|
|
|
|
1 |
|
|
2 |
5 |
3 |
4 |
|
|
1 |
|
|
|
6 |
7 |
|
|
8 |
采用CLOCK算法:缺页次数:13次
|
1 |
2 |
3 |
4 |
5 |
3 |
4 |
1 |
6 |
7 |
8 |
7 |
8 |
9 |
7 |
8 |
9 |
5 |
4 |
5 |
4 |
2 |
|
缺 |
缺 |
缺 |
缺 |
缺 |
|
|
缺 |
缺 |
缺 |
缺 |
|
|
缺 |
|
|
|
缺 |
缺 |
|
|
缺 |
< |
1* |
1* |
1* |
1*< |
5* |
5* |
5* |
5* |
5 |
5< |
8* |
8* |
8* |
8* |
8* |
8* |
8* |
8 |
8< |
8< |
8< |
2* |
|
< |
2* |
2* |
2* |
2< |
2< |
2< |
1* |
1 |
1 |
1< |
1< |
1< |
9* |
9* |
9* |
9* |
9 |
9 |
9 |
9 |
9< |
|
|
< |
3* |
3* |
3 |
3* |
3* |
3*< |
6* |
6* |
6* |
6* |
6* |
6*< |
6*< |
6*< |
6*< |
5* |
5* |
5* |
5* |
5* |
|
|
|
< |
4* |
4 |
4 |
4* |
4* |
4< |
7* |
7* |
7* |
7* |
7* |
7* |
7* |
7* |
7< |
4 |
4 |
4* |
4* |
换出 |
|
|
|
|
1 |
|
|
2 |
3 |
4 |
5 |
|
|
1 |
|
|
|
6 |
7 |
|
|
8 |
页号 |
物理块号 |
是否在TLB |
0 |
8 |
是 |
1 |
7 |
是 |
2 |
4 |
否 |
3 |
10 |
否 |
4 |
5 |
否 |
5 |
3 |
是 |
6 |
2 |
是 |
(1)计算两个逻辑地址:0AC5H、1AC5H对应的物理地址。
(2)已知主存的一次存取为1.5us,对于TLB表(快表)的查询时间可以忽略,则访问上述两个逻辑地址共耗费多少时间?
解答:(1)0AC5H:转换为二进制地址:101011000101,低10位为页内地址,所以页号为2,查页表,得块号为4,则物理地址为:1001011000101,即12C5H(4805);
1AC5H:转换为二进制地址:1101011000101,低10位为页内地址,所以页号为6,查页表,得块号为2,则物理地址为:101011000101,即0AC5H(2757)
(2)访问0AC5H:不在快表,两次访问内存:3us;访问1AC5H,在快表,访问一次内存,1.5us,所以总共4.5us
简答:一个索引块能存块号数量:4K/4=1K
三级索引块数量:1
二级索引块数量:1 + 1 * 1K
一级索引块数量: 1 + ( 1 + 1 * 1K) * 1K
数据块数量:(1 + ( 1 + 1 * 1K) * 1K)*1K + 10
文件大小:((1 + ( 1 + 1 * 1K) * 1K)*1K + 10)*4K
> 1K * 1K *1K * 4K = 4T
(1) 若采用隐式链接,按顺序写出对磁盘的操作步骤及相应磁道号。
(2) 若采用FAT分配方法,FAT表存储在磁盘开始的位置,每个FAT表项占4B。现在要在720号磁道上为该文件尾部追加数据,按顺序写出对磁盘的操作步骤及相应磁道号。
解答:
(1) 9->51->60->120->21->900->300
(2) 2MB/1KB = 2K块
1KB/4B ,每个数据块存放256个FAT表项。2K个FAT表项共占据8个磁盘块
0-255 第0块;256-511第1块;512-767第2块;768-1023第3块
60,120,21在第0个FAT块, 300在第1个FAT块,900在第3个FAT块
因此,访问顺序9->51->0(读取60,120,21,900)->3(读取300)->1(FAT第300项写入720)->2(写入休止符)->720块追加数据
简答:位示图需要的字节数计算:INT(40GB/4KB)/ 8
2^23<10*2^20 <2^24 24位,3字节。FAT表大小 = 3 * 10*2^20 = 30MB
(1)基本目录项大小为多少字节?
(2)假设某一目录文件共有254个FCB,试分别给出采用分解法之前和之后,对该目录文件分别的平均访问磁盘次数(最大访问磁盘次数除以2):
解答:
(1)基本目录项大小为多少字节? 64-8=56B
(2)假设某一目录文件共有254个FCB,试分别给出采用分解法之前和之后,对该目录文件分别的平均访问磁盘次数:
答:
分解前:FCB占用块数:254*64/512=32块,平均访问磁盘次数:(1+32)/2=16.5
分解后:FCB占用块数:254*10/512=5块,平均访问磁盘次数:(1+5)/2+1=4
1.安装Linux虚拟机,熟悉Linux基本命令
man命令:shenkan@shenkan-virtual-machine:~$ man ls
输出反馈:ls命令的详细内容
sudo命令:shenkan@shenkan-virtual-machine:~$ sudo -h
输出反馈:切换用户身份命令的帮助
pwd命令:shenkan@shenkan-virtual-machine:~$ pwd
输出反馈:/home/shenkan
cd命令:shenkan@shenkan-virtual-machine:~$ cd /
输出反馈:无反馈
再次执行pwd命令,当前工作目录改变为:/目录
2.实现一个模拟shell
(1)编写三个不同的程序:cmd1.c, cmd2.c, cmd3.c分别编译成可执行文件cmd1, cmd2, cmd3
(2)编写主程序,模拟shell程序的功能,能根据用户输入的字符串(表示相应的命令名),去为相应的命令创建子进程并让它去执行相应的程序,而父进程则等待子进程的结束,然后再等待接收下一条命令。如果接收到的命令为exit,则父进程结束,如果接收到无效命令,则显示”command not found”,继续等待。
(3)在主函数编写中
pid = fork()会返回多个值,只需在fork()后使用多个判断语句即可。
pid<0表示错误,打印error之后退出
pid=0表示子进程运行,使用execl替换进程,替换为我们想要的进程,如cmd1.o。
pid>0表示父进程运行,使用wait(NULL)函数等待所有子进程的退出。
//test1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
char input[20];
pid_t pid=0;
// printf("输入要运行的程序名$\n");
// scanf("%s", input);
while(1)
{
printf("输入要运行的程序名$\n");
scanf("%s", input);
if(strcmp(input,"exit") == 0)
{
printf("父进程退出\n");
printf("\n进程结束,pid:%d\n", getpid());
exit(0);
}
else if(strcmp(input,"cmd3") == 0 || strcmp(input,"cmd2") == 0 || strcmp(input,"cmd1") == 0)
{
//创建子进程
pid = fork();
if(pid < 0)
{
printf("vfork() error\n");
exit(-1);
}
else if(pid == 0)
{
printf("This is son, his pid is: %d\n", getpid());
char path[80] = "/home/osclass/Class/test3/1/cmd/";
char *lastName = ".o";
strcat(path, input);
strcat(path, lastName);
execl(path,"",NULL);
}
else
{
printf("This is father, his pid is: %d\n", getpid());
pid_t temp = wait(NULL);
printf("\n进程结束,pid:%d\n", temp);
}
}
else
{
printf("Command not found\n");
// printf("输入要运行的程序名$\n");
// scanf("%s", input);
continue;
}
}
return 0;
}
结果
3.实现一个管道通信程序
//test2
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#define READ 0 //filedes[0]用于读
#define WRITE 1 //filedes[1]用于写
int main() {
/*
函数原型:pipe(int filedes[2])
参数含义:filedes[0]对应管道读端,filedes[1]对应管道写端
功能:pipe在内存缓冲区中创建一个管道,并将读写该管道的一对文件描述符保存在filedes所指数组中
返回值:成功返回0,失败返回-1
*/
int filedes[2];
pid_t pid1,pid2,pid3;//pid_t本质就是int
char buf[256]; //用作read的缓冲区,保存读取的字符
pipe(filedes); //创建无名管道
//改进的地方
pid1=1;pid2=1;pid3=1;
pid1 = fork();
if(pid1>0) pid2=fork();
if(pid1>0&&pid2>0) pid3=fork();
if (pid1 == 0) {
sleep(1);
printf("正在产生子进程pid1:%d\n",getpid());
close(filedes[READ]);
write(filedes[WRITE], "pid1\n", strlen("pid1\n"));
exit(0);
}
if(pid2 == 0) {
sleep(1); //挂起一秒
printf("正在产生子进程pid2:%d\n",getpid());
//子进程向父进程写数据,关闭管道的读端
close(filedes[READ]);
write(filedes[WRITE], "pid2\n", strlen("pid2\n"));
exit(0);
}
if (pid3 == 0) {
sleep(1);
printf("正在产生子进程pid3:%d\n",getpid());
close(filedes[READ]);
write(filedes[WRITE], "pid3\n", strlen("pid3\n"));
exit(0);
}
else {
//waitpid()会暂时停止目前进程的执行,直到有信号来或者子进程结束
pid1 = waitpid(pid1, NULL, WUNTRACED);
pid2 = waitpid(pid2, NULL, WUNTRACED);
pid3 = waitpid(pid3, NULL, WUNTRACED);
printf("main pid: %d\n",getpid());
printf("wait pid: %d %d %d 返回信息\n",pid1,pid2,pid3);
/*父进程从管道读取子进程写的数据,关闭管道的写端*/
close(filedes[WRITE]);
//read():读取的数据保存在缓冲区buf
read(filedes[READ], buf, sizeof(buf));
printf("3个子进程传输的数据为:\n%s\n", buf);
}
return 0;
}
结果
4.利用Linux消息队列通信机制实现两个线程间的通信
命令:vim a.c
//a.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct MSG{
long mtype;//消息类型
char buf[100];//消息数据
};
struct MSG_read{
long mtype_read;//消息类型
char buf_read[100];//消息数据
};
void *write1(void *arg)
{
//1.获取key
key_t key = ftok("/",‘a‘);
if(key==-1)
{
perror("ftok");
exit(-1);
}
int msqid = msgget(key,IPC_CREAT|0666); //2.通过key创建消息队列
if(msqid==-1)
{
perror("msgget");
exit(-2);
}
//3.发送消息
struct MSG msg1;
while(1)
{
msg1.mtype = 1;
fgets(msg1.buf,100,stdin);
int res = msgsnd(msqid,&msg1,sizeof(msg1.buf),0);
}
}
void *read1(void *arg)
{
key_t key = ftok("/",‘b‘);
if(key==-1)
{
perror("ftok");
exit(-1);
}
int msqid = msgget(key,IPC_CREAT|0666); //2.通过key创建消息队列
if(msqid==-1)
{
perror("msgget");
exit(-2);
}
struct MSG_read msg;
while(1)
{
int res = msgrcv(msqid,&msg,sizeof(msg.buf_read),2,0); //收类型为2 的信息
if(res==-1){
perror("msgrcv");
exit(-3);
}
printf("%s",msg.buf_read);
}
}
int main()
{
pthread_t id1;
pthread_t id2;
//创建线程
int res = pthread_create(&id1,0,write1,0);
if(res){
printf("%s\n",strerror(res));
//exit(-1);
}
int res2 = pthread_create(&id2,0,read1,0);
if(res2){
printf("%s\n",strerror(res2));
//exit(-1);
}
pthread_join(id1,0);
pthread_join(id2,0);
return 0;
}
命令:vim b.c
//b.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct MSG{
long mtype;//消息类型
char buf[100];//消息数据
};
struct MSG_read{
long mtype_read;//消息类型
char buf_read[100];//消息数据
};
void *read2(void *arg)
{
//1.获取key
key_t key = ftok("/",‘a‘);
if(key==-1)
{
perror("ftok");
exit(-1);
}
int msqid = msgget(key,IPC_CREAT|0666); //2.通过key创建消息队列
if(msqid==-1)
{
perror("msgget");
exit(-2);
}
struct MSG msg1;
while(1)
{
int res = msgrcv(msqid,&msg1,sizeof(msg1.buf),1,0); //收类型为2 的信息
if(res==-1){
perror("msgrcv");
exit(-3);
}
printf("%s",msg1.buf);
}
}
void *write2(void *arg)
{
key_t key = ftok("/",‘b‘);
if(key==-1)
{
perror("ftok");
exit(-1);
}
int msqid = msgget(key,IPC_CREAT|0666); //2.通过key创建消息队列
if(msqid==-1)
{
perror("msgget");
exit(-2);
}
struct MSG_read msg1;
msg1.mtype_read = 2;
while(1)
{
fgets(msg1.buf_read,100,stdin);
int res = msgsnd(msqid,&msg1,sizeof(msg1.buf_read),0);
}
}
int main()
{
pthread_t id1;
pthread_t id2;
//创建线程
int res = pthread_create(&id1,0,write2,0);
if(res){
printf("%s\n",strerror(res));
//exit(-1);
}
int res2 = pthread_create(&id2,0,read2,0);
if(res2){
printf("%s\n",strerror(res2));
//exit(-1);
}
pthread_join(id1,0);
pthread_join(id2,0);
return 0;
}
命令:vim Makefile
//Makefile
all:a.c b.c
gcc a.c -pthread -o b.out
gcc b.c -pthread
命令:make
打开另一个终端窗口。分别键入命令:./a.out和./b.out
5.利用Linux共享内存通信机制实现两个进程间的通信
//sender.c
#include "common.h"
#include <stdio.h>
key_t key;
int shmid;
char * shmptr;
char input[SHM_SIZE];
sem_t * full;
sem_t * mutex;
void Init()
{
key = KEY_NUM;
shmid = GetShmId(key);
shmptr = shmat(shmid,NULL,0);
//semaphore init
full = sem_open(FULL_NAME,O_CREAT);
mutex = sem_open(MUTEX_NAME,O_CREAT);
}
void SaveMessage()
{
P(mutex);
strcpy(shmptr,input);
V(mutex);
V(full);
}
int main(int argc, char const *argv[])
{
init();
fgets(input, 1024, stdin);
SaveMessage();
printf("Sender: Process End\n");
return 0;
}
//receiver.c
#include "common.h"
key_t key;
int shmid;
char * shmptr;
char result[SHM_SIZE];
sem_t * full;
sem_t * mutex;
void Init()
{
key = KEY_NUM;
shmid = GetShmId(key);
shmptr = shmat(shmid,NULL,0);
full = sem_open(FULL_NAME,O_CREAT);
mutex = sem_open(MUTEX_NAME,O_CREAT);
}
void ReadMessage()
{
P(full);
P(mutex);
strcpy(result,shmptr);
V(mutex);
}
int main(int argc, char const *argv[])
{
Init();
ReadMessage();
printf("Receiver : message is %s\n",result);
SemDestroy();
printf("Receiver : Process End \n");
return 0;
}
Makefile
all : init sender receiver
.PHONY : clean
init : init.o common.o
cc -pthread -o init init.o common.o
sender : sender.o common.o
cc -pthread -o sender sender.o common.o
receiver : receiver.o common.o
cc -pthread -o receiver receiver.o common.o
init.o : common.h
sender.o : common.h
receiver.o : common.h
clean :
rm init
rm receiver
rm sender
rm *.o
结果
6.简单的文件系统
(1)在内存中开辟一个虚拟磁盘空间作为文件存储分区,在其上实现一个简单的基于多级目录的单用户单任务系统中的文件系统。在退出该文件系统的使用时,应将该虚拟文件系统以一个文件的方式保存到磁盘上,以便下次可以再将它恢复到内存的虚拟磁盘空间中。
(2)文件存储空间的分配可采用显式链接分配或其他的办法。
(3)空闲磁盘空间的管理可选择位示图或其他的办法。如果采用位示图来管理文件存储空间,并采用显式链接分配方式,那么可以将位示图合并到FAT中。
(4)文件目录结构采用多级目录结构。为了简单起见,可以不使用索引结点,其中的每个目录项应包含文件名、物理地址、长度等信息,还可以通过目录项实现对文件的读和写的保护。
(5)要求提供以下操作命令:
1)my_format:对文件存储器进行格式化,即按照文件系统的结构对虚拟磁盘空间进行布局,并在其上创建根目录以及用于管理文件存储空间等的数据结构。
2)my_mkdir:用于创建子目录。
3)my_rmdir:用于删除子目录。
4)my_ls:用于显示目录中的内容。
5)my_cd:用于更改当前目录。
6)my_create:用于创建文件。
7)my_open:用于打开文件。
8)my_close:用于关闭文件。
9)my_write:用于写文件。
10)my_read:用于读文件。
11)my_rm:用于删除文件。
12)my_exitsys:用于退出文件系统。
核心代码:
在自己的文件系统里创建一个liuxinrui文件夹,并在这个文件夹里创建一个名为1.txt的txt文本,运用“write”命令写入文本后再使用“read”命令对1.txt文本的内容进行读取。
代码参考:https://blog.csdn.net/qq_36285879/article/details/88771691
https://wenku.baidu.com/view/df9f1440b4daa58da1114a2e.html
标签:字节 目录 mdi fork eof 进入 linux共享内存 last 内容
原文地址:https://www.cnblogs.com/Sknife/p/13300990.html