first commit
This commit is contained in:
commit
5f1b6a7b06
BIN
Assignment/Assignment1/21281280-柯劲帆-课后习题1.pdf
Normal file
BIN
Assignment/Assignment1/21281280-柯劲帆-课后习题1.pdf
Normal file
Binary file not shown.
107
Assignment/Assignment1/source/21281280-柯劲帆-课后习题1.md
Normal file
107
Assignment/Assignment1/source/21281280-柯劲帆-课后习题1.md
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<h1><center>课程作业</center></h1>
|
||||||
|
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">课程名称</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">操作系统</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">作业名称</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">课后习题1</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">学号</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">21281280</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">姓名</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">柯劲帆</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">班级</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">物联网2101班</span></div>
|
||||||
|
</div>
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 问题1
|
||||||
|
|
||||||
|
**哲学家进餐问题的变形。假设5支筷子都放在圆桌的中间,哲学家进餐时拿起任意两支筷子就可以进餐。其他条件不变。请用信号量实现5个哲学家进程的同步。**
|
||||||
|
|
||||||
|
```pascal
|
||||||
|
Var
|
||||||
|
chopsticks, eating_philosophers: Semaphore := 5, 4;
|
||||||
|
|
||||||
|
Procedure Philosopher(i: integer);
|
||||||
|
Begin
|
||||||
|
Repeat
|
||||||
|
wait(eating_philosophers);
|
||||||
|
wait(chopsticks);
|
||||||
|
wait(chopsticks);
|
||||||
|
|
||||||
|
Eat;
|
||||||
|
|
||||||
|
signal(chopsticks);
|
||||||
|
signal(chopsticks);
|
||||||
|
signal(eating_philosophers);
|
||||||
|
|
||||||
|
Think;
|
||||||
|
|
||||||
|
Until False;
|
||||||
|
End;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 问题2
|
||||||
|
|
||||||
|
**四个进程P0,P1,P2,P3和四个信箱M0,M1,M2,M3进程间借助相邻的信箱传递消息:Pi每次从Mi中取出一条消息,经加工送入Mi+1(mod 4)中。其中M0,M1,M2,M3分别设有3,3,2,2个格子,每个格子放一条消息,初始时,M0装满了三条消息,其余为空。写出使用信号量实现进程 (i=0,1,2,3)同步的算法。**
|
||||||
|
|
||||||
|
```pascal
|
||||||
|
Var
|
||||||
|
full, empty, mutex: array[0..3] of Semaphore := (3, 0, 0, 0), (0, 3, 2, 2), (1, 1, 1, 1);
|
||||||
|
|
||||||
|
Procedure ProcessPi(i: integer);
|
||||||
|
Var
|
||||||
|
message: Message;
|
||||||
|
Begin
|
||||||
|
Repeat
|
||||||
|
wait(full[i]);
|
||||||
|
wait(mutex[i]);
|
||||||
|
message := Get_Message_From_Mailbox(i);
|
||||||
|
signal(mutex[i]);
|
||||||
|
signal(empty[i]);
|
||||||
|
|
||||||
|
ProcessMessage;
|
||||||
|
|
||||||
|
wait(empty[(i + 1) mod 4]);
|
||||||
|
wait(mutex[(i + 1) mod 4]);
|
||||||
|
Send_Message_To_Mail_box((i + 1) mod 4, message);
|
||||||
|
signal(mutex[(i + 1) mod 4]);
|
||||||
|
signal(full[(i + 1) mod 4]);
|
||||||
|
|
||||||
|
Until False;
|
||||||
|
End;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 问题3
|
||||||
|
|
||||||
|
**汽车司机与售票员之间必须协同工作,汽车每到一个站后,一方面,只有当司机已经停下,售票员才能开门上下客,另一方面,只有售票员把车门关好了司机才能开车。假定某辆公共汽车上有前后门各有一名售票员以及一名司机,汽车初始状态是正在始发站停车上客。试设必要的信号量及赋初值,实现售票员进程和司机进程的同步。**
|
||||||
|
|
||||||
|
```pascal
|
||||||
|
Var
|
||||||
|
driver, ticket_seller: Semaphore := 1, 2;
|
||||||
|
|
||||||
|
Procedure Driver;
|
||||||
|
Begin
|
||||||
|
Repeat
|
||||||
|
wait(driver);
|
||||||
|
|
||||||
|
Move;
|
||||||
|
|
||||||
|
Stop;
|
||||||
|
|
||||||
|
signal(ticket_seller);
|
||||||
|
signal(ticket_seller);
|
||||||
|
|
||||||
|
Until False;
|
||||||
|
End;
|
||||||
|
|
||||||
|
Procedure Ticket_seller(i: integer);
|
||||||
|
Begin
|
||||||
|
Repeat
|
||||||
|
wait(ticket_seller);
|
||||||
|
wait(ticket_seller);
|
||||||
|
|
||||||
|
Open;
|
||||||
|
|
||||||
|
signal(driver);
|
||||||
|
|
||||||
|
Close;
|
||||||
|
|
||||||
|
Until False;
|
||||||
|
End;
|
||||||
|
```
|
BIN
Courseware/1. 操作系统引论-1.ppt
Normal file
BIN
Courseware/1. 操作系统引论-1.ppt
Normal file
Binary file not shown.
BIN
Courseware/1. 操作系统引论-2.ppt
Normal file
BIN
Courseware/1. 操作系统引论-2.ppt
Normal file
Binary file not shown.
BIN
Courseware/2. 进程管理-1.ppt
Normal file
BIN
Courseware/2. 进程管理-1.ppt
Normal file
Binary file not shown.
BIN
Courseware/2. 进程管理-2.ppt
Normal file
BIN
Courseware/2. 进程管理-2.ppt
Normal file
Binary file not shown.
BIN
Courseware/2. 进程管理-3.ppt
Normal file
BIN
Courseware/2. 进程管理-3.ppt
Normal file
Binary file not shown.
BIN
Courseware/3. 处理机调度.ppt
Normal file
BIN
Courseware/3. 处理机调度.ppt
Normal file
Binary file not shown.
BIN
Courseware/3. 死锁.ppt
Normal file
BIN
Courseware/3. 死锁.ppt
Normal file
Binary file not shown.
BIN
Courseware/4.1.连续分配.ppt
Normal file
BIN
Courseware/4.1.连续分配.ppt
Normal file
Binary file not shown.
BIN
Courseware/4.2.分页分段.ppt
Normal file
BIN
Courseware/4.2.分页分段.ppt
Normal file
Binary file not shown.
BIN
Courseware/4.3.虚拟存储器.ppt
Normal file
BIN
Courseware/4.3.虚拟存储器.ppt
Normal file
Binary file not shown.
BIN
Courseware/5.1.设备管理-概念.ppt
Normal file
BIN
Courseware/5.1.设备管理-概念.ppt
Normal file
Binary file not shown.
BIN
Courseware/5.2.设备管理-共性技术.ppt
Normal file
BIN
Courseware/5.2.设备管理-共性技术.ppt
Normal file
Binary file not shown.
BIN
Courseware/5.3.设备管理-磁盘.ppt
Normal file
BIN
Courseware/5.3.设备管理-磁盘.ppt
Normal file
Binary file not shown.
BIN
Courseware/6.1.文件系统.ppt
Normal file
BIN
Courseware/6.1.文件系统.ppt
Normal file
Binary file not shown.
BIN
Courseware/6.2.文件系统.ppt
Normal file
BIN
Courseware/6.2.文件系统.ppt
Normal file
Binary file not shown.
BIN
Courseware/6.3.文件系统.ppt
Normal file
BIN
Courseware/6.3.文件系统.ppt
Normal file
Binary file not shown.
BIN
Lab/Lab1/21281280-柯劲帆-第1次实验.pdf
Normal file
BIN
Lab/Lab1/21281280-柯劲帆-第1次实验.pdf
Normal file
Binary file not shown.
707
Lab/Lab1/material/21281280-柯劲帆-第1次实验.md
Normal file
707
Lab/Lab1/material/21281280-柯劲帆-第1次实验.md
Normal file
@ -0,0 +1,707 @@
|
|||||||
|
<h1><center>北京交通大学实验报告</center></h1>
|
||||||
|
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">课程名称</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">操作系统</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">实验题目</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">操作系统并发特征验证性实验</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">学号</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">21281280</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">姓名</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">柯劲帆</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">班级</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">物联网2101班</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">指导老师</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">何永忠</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">报告日期</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">2023年10月8日</span></div>
|
||||||
|
</div>
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 1. 开发运行环境和工具
|
||||||
|
|
||||||
|
| 操作系统 | Linux内核版本 | 处理器 | GCC版本 |
|
||||||
|
| :---------: | :-----------------------: | :----------------------------------------------------------: | :-------------------------------: |
|
||||||
|
| Deepin 20.9 | 5.18.17-amd64-desktop-hwe | 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz (8核,非大小核) | gcc (Uos 8.3.0.3-3+rebuild) 8.3.0 |
|
||||||
|
|
||||||
|
- **其他工具**:
|
||||||
|
- **strace**:version 4.26
|
||||||
|
- **编辑**:VSCode (version 1.82.2)
|
||||||
|
- **编译和运行**:Terminal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2. 实验过程
|
||||||
|
|
||||||
|
### 2.1. 阅读算法
|
||||||
|
|
||||||
|
**算法逻辑写在以下的代码注释中。**
|
||||||
|
|
||||||
|
**头文件。**三份源码都相同。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
// 引用线程库、标准输入输出库、标准库和时间库
|
||||||
|
```
|
||||||
|
|
||||||
|
**宏定义操作、定义循环变量和共享全局变量。**三份源码都相同。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
typedef char _bool;
|
||||||
|
#define _true (char)1
|
||||||
|
#define _false (char)0
|
||||||
|
#define LOG printf("author: 柯劲帆\n")
|
||||||
|
// 宏定义一些操作
|
||||||
|
const int LOOP_NUM = 10000000;
|
||||||
|
// 定义循环次数
|
||||||
|
volatile int nAccount1, nAccount2, turn;
|
||||||
|
// 创建三个变量用于模拟两个账户和线程并发执行的控制,是临界资源
|
||||||
|
// volatile关键字表示这些变量有可能在本程序以外被修改,每次访问这些变量都需要到内存中读取。
|
||||||
|
```
|
||||||
|
|
||||||
|
**主程序。**三份源码都相同。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
clock_t start, end;
|
||||||
|
start = clock(); // 记录程序开始时间
|
||||||
|
pthread_t th1, th2;
|
||||||
|
pthread_create(&th1, NULL, transA, NULL);
|
||||||
|
pthread_create(&th2, NULL, transB, NULL);
|
||||||
|
// 创建两个线程,分别执行transA和transB
|
||||||
|
pthread_join(th1, NULL);
|
||||||
|
pthread_join(th2, NULL);
|
||||||
|
// 等待两个线程完成
|
||||||
|
end = clock(); // 获取程序结束时间
|
||||||
|
printf("program running time: %lf\n", ((double)(end - start)) / CLOCKS_PER_SEC);
|
||||||
|
// 打印程序运行时间,这个时间包括了:1.两个线程实际运行的时间之和;2.被其他CPU任务阻塞的时间
|
||||||
|
LOG;
|
||||||
|
// 输出结束信息
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**none_sync.cpp**的tranA / transB函数。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void* transA(void* arg) {
|
||||||
|
int nLoop = 0; // 定义循环变量
|
||||||
|
int nTemp1, nTemp2, nRandom; // 定义过程记录变量和随机变量
|
||||||
|
do {
|
||||||
|
nRandom = rand() % 10000; // 为随机变量赋值
|
||||||
|
// === 临界区开始 ===
|
||||||
|
nTemp1 = nAccount1;
|
||||||
|
nTemp2 = nAccount2;
|
||||||
|
nAccount1 = nTemp1 + nRandom;
|
||||||
|
nAccount2 = nTemp2 - nRandom;
|
||||||
|
// 对两个账户进行转账操作
|
||||||
|
// === 临界区结束 ===
|
||||||
|
nLoop += 1;
|
||||||
|
if (nAccount1 + nAccount2 != 0) {
|
||||||
|
printf("error\n");
|
||||||
|
return NULL;
|
||||||
|
} // 如果两个账户之和不为0,即程序出错,退出程序
|
||||||
|
} while (nLoop <= LOOP_NUM);
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**linux_sync.cpp**的tranA / transB函数。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
// 创建一个互斥锁,这个锁将用于保护共享资源的访问,以防止多线程竞争条件
|
||||||
|
void* transA(void* arg)
|
||||||
|
{
|
||||||
|
int nLoop = 0;
|
||||||
|
int nTemp1, nTemp2, nRandom;
|
||||||
|
do {
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
// 锁定互斥锁以保护临界区
|
||||||
|
nRandom = rand() % 10000;
|
||||||
|
// === 临界区开始 ===
|
||||||
|
nTemp1 = nAccount1;
|
||||||
|
nTemp2 = nAccount2;
|
||||||
|
nAccount1 = nTemp1 + nRandom;
|
||||||
|
nAccount2 = nTemp2 - nRandom;
|
||||||
|
// === 临界区结束 ===
|
||||||
|
nLoop += 1;
|
||||||
|
if (nAccount1 + nAccount2 != 0) {
|
||||||
|
printf("error\n");
|
||||||
|
return NULL;
|
||||||
|
} // 如果两个账户之和不为0,即程序出错,退出程序
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
// 解锁互斥锁
|
||||||
|
} while (nLoop <= LOOP_NUM);
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**peterson.cpp**的tranA / transB函数。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
volatile _bool flag[2];
|
||||||
|
// 设置旗标变量
|
||||||
|
void* transA(void* arg)
|
||||||
|
{
|
||||||
|
int nLoop = 0;
|
||||||
|
int nTemp1, nTemp2, nRandom;
|
||||||
|
do {
|
||||||
|
flag[0] = _true; // 标志本线程已准备好进入临界区
|
||||||
|
turn = 1; // 将turn设置为另一个线程的标号
|
||||||
|
while (turn == 1 && flag[1] == _true);
|
||||||
|
// 进入临界区前,检查另一个线程的flag是否为1,且turn不等于自己的标号
|
||||||
|
// 如果另一个线程也正在等待,且轮到它,则循环等待
|
||||||
|
nRandom = rand() % 10000;
|
||||||
|
// === 临界区开始 ===
|
||||||
|
nTemp1 = nAccount1;
|
||||||
|
nTemp2 = nAccount2;
|
||||||
|
nAccount1 = nTemp1 + nRandom;
|
||||||
|
nAccount2 = nTemp2 - nRandom;
|
||||||
|
// === 临界区结束 ===
|
||||||
|
nLoop += 1;
|
||||||
|
if (nAccount1 + nAccount2 != 0) {
|
||||||
|
printf("error\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
flag[0] = _false;
|
||||||
|
// 当线程执行完临界区代码后,将自己的flag置为0,表示已经离开了临界区
|
||||||
|
} while (nLoop <= LOOP_NUM);
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2. 编译运行
|
||||||
|
|
||||||
|
在命令行中分别编译3份代码。命令行提示信息、命令如下。均无输出。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ g++ ./none_sync.cpp -o ./none_sync -pthread
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ g++ ./linux_sync.cpp -o ./linux_sync -pthread
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ g++ ./peterson.cpp -o ./peterson -pthread
|
||||||
|
```
|
||||||
|
|
||||||
|
运行第1份程序,命令行提示信息、命令和输出如下。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ ./none_sync
|
||||||
|
error
|
||||||
|
error
|
||||||
|
program running time: 0.000212
|
||||||
|
author: 柯劲帆
|
||||||
|
```
|
||||||
|
|
||||||
|
运行第2份程序,命令行提示信息、命令和输出如下。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ ./linux_sync
|
||||||
|
program running time: 4.596819
|
||||||
|
author: 柯劲帆
|
||||||
|
```
|
||||||
|
|
||||||
|
运行第3份程序,命令行提示信息、命令和输出如下。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ ./peterson
|
||||||
|
program running time: 3.736581
|
||||||
|
author: 柯劲帆
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3. 修改并运行none_sync.cpp代码
|
||||||
|
|
||||||
|
修改代码,打印各个变量以观察变量的修改状况。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
do {
|
||||||
|
nRandom = rand() % 10000;
|
||||||
|
nTemp1 = nAccount1;
|
||||||
|
printf("[transA:%d] nTemp1 = %d\n", nLoop, nTemp1);
|
||||||
|
nTemp2 = nAccount2;
|
||||||
|
printf("[transA:%d] nTemp2 = %d\n", nLoop, nTemp2);
|
||||||
|
nAccount1 = nTemp1 + nRandom;
|
||||||
|
printf("[transA:%d] nAccount1 = %d + %d = %d\n", nLoop, nTemp1, nRandom, nTemp1 + nRandom);
|
||||||
|
nAccount2 = nTemp2 - nRandom;
|
||||||
|
printf("[transA:%d] nAccount2 = %d - %d = %d\n", nLoop, nTemp2, nRandom, nTemp2 - nRandom);
|
||||||
|
nLoop += 1;
|
||||||
|
if (nAccount1 + nAccount2 != 0) {
|
||||||
|
printf("error\n");
|
||||||
|
printf("[transA] nTemp1=%d, nTemp2=%d, nRandom=%d, nTemp1+nRandom=%d, nTemp2-nRandom=%d, nAccount1=%d, nAccount2=%d\n", nTemp1, nTemp2, nRandom, nTemp1 + nRandom, nTemp2 - nRandom, nAccount1, nAccount2);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} while (nLoop <= LOOP_NUM);
|
||||||
|
```
|
||||||
|
|
||||||
|
编译并运行。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ g++ ./none_sync.cpp -o ./none_sync -pthread && ./none_sync
|
||||||
|
```
|
||||||
|
|
||||||
|
截取error部分和main部分的输出如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
error
|
||||||
|
[transA] nTemp1=41171, nTemp2=-21, nRandom=59, nTemp1+nRandom=41230, nTemp2-nRandom=-80, nAccount1=41230, nAccount2=-80
|
||||||
|
error
|
||||||
|
[transB] nTemp1=16, nTemp2=-16, nRandom=5, nTemp1+nRandom=21, nTemp2-nRandom=-21, nAccount1=41230, nAccount2=-80
|
||||||
|
program running time: 0.000237
|
||||||
|
author: 柯劲帆
|
||||||
|
```
|
||||||
|
|
||||||
|
**完整输出见附录”7.1. none_sync_1程序的完整输出“。**
|
||||||
|
|
||||||
|
### 2.4. 修改并运行linux_sync.cpp和peterson.cpp代码
|
||||||
|
|
||||||
|
将linux_sync.cpp代码的do-while循环部分修改如下。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
do {
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
nRandom = rand() % 10;
|
||||||
|
nTemp1 = nAccount1;
|
||||||
|
nTemp2 = nAccount2;
|
||||||
|
nAccount1 = nTemp1 + nRandom;
|
||||||
|
nAccount2 = nTemp2 - nRandom;
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
} while ((nAccount1 + nAccount2) == 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
编译并运行。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ g++ ./linux_sync_1.cpp -o ./none_sync_1 -pthread && ./linux_sync_1
|
||||||
|
```
|
||||||
|
|
||||||
|
程序一直运行不停止,直至在命令行输入`ctrl+C`才退出。
|
||||||
|
|
||||||
|
将peterson.cpp代码的transA函数do-while循环部分修改如下。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
do {
|
||||||
|
flag[0] = _true;
|
||||||
|
turn = 1;
|
||||||
|
while (turn == 1 && flag[1] == _true);
|
||||||
|
nRandom = rand() % 10000;
|
||||||
|
nTemp1 = nAccount1;
|
||||||
|
nTemp2 = nAccount2;
|
||||||
|
nAccount1 = nTemp1 + nRandom;
|
||||||
|
nAccount2 = nTemp2 - nRandom;
|
||||||
|
flag[0] = _false;
|
||||||
|
} while ((nAccount1 + nAccount2) == 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
transB函数作类似更改,不同之处在于上述代码第3行`turn = 0;`和第4行`while (turn == 0 && flag[0] == _true);`。
|
||||||
|
|
||||||
|
编译并运行。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ g++ ./peterson_1.cpp -o ./peterson_1 -pthread && ./peterson_1
|
||||||
|
```
|
||||||
|
|
||||||
|
程序一直运行不停止,直至在命令行输入`ctrl+C`才退出。
|
||||||
|
|
||||||
|
### 2.5. 分别多次运行linux_sync程序和peterson程序比较运行时间
|
||||||
|
|
||||||
|
多次在命令行中运行linux_sync程序和peterson程序,将输出的运行时间记录。
|
||||||
|
|
||||||
|
所有的运行结果均没有error提示信息打印出来,说明以下的运行时间均为do-while循环内临界区运行了一共$2 \times 10000000$次的时间。
|
||||||
|
|
||||||
|
| 程序 | 第1次运行用时/s | 第2次运行用时/s | 第3次运行用时/s | 第4次运行用时/s | 第5次运行用时/s | 第6次运行用时/s | 平均运行用时/s |
|
||||||
|
| :------------: | :-------------: | :-------------: | :-------------: | :-------------: | :-------------: | :-------------: | :------------: |
|
||||||
|
| **linux_sync** | 5.829870 | 3.351867 | 4.729514 | 3.930167 | 5.229939 | 4.624409 | **4.615961** |
|
||||||
|
| **peterson** | 3.757013 | 3.428822 | 3.420579 | 2.483765 | 5.445688 | 4.487762 | **3.837272** |
|
||||||
|
|
||||||
|
### 2.6. 使用strace工具观察linux_sync程序和peterson程序的系统调用情况
|
||||||
|
|
||||||
|
在终端中调用strace工具分析linux_sync程序和peterson程序的系统调用情况。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ strace -c ./linux_sync
|
||||||
|
program running time: 4.172697
|
||||||
|
author: 柯劲帆
|
||||||
|
% time seconds usecs/call calls errors syscall
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
99.99 1.971464 1971464 1 futex
|
||||||
|
0.00 0.000060 2 29 mmap
|
||||||
|
0.00 0.000030 2 12 mprotect
|
||||||
|
0.00 0.000022 11 2 clone
|
||||||
|
0.00 0.000013 2 6 openat
|
||||||
|
0.00 0.000008 8 1 munmap
|
||||||
|
0.00 0.000006 1 5 read
|
||||||
|
0.00 0.000006 1 6 close
|
||||||
|
0.00 0.000006 0 7 fstat
|
||||||
|
0.00 0.000005 2 2 write
|
||||||
|
0.00 0.000004 2 2 clock_gettime
|
||||||
|
0.00 0.000003 1 3 brk
|
||||||
|
0.00 0.000003 3 1 1 access
|
||||||
|
0.00 0.000002 1 2 rt_sigaction
|
||||||
|
0.00 0.000002 2 1 execve
|
||||||
|
0.00 0.000001 1 1 rt_sigprocmask
|
||||||
|
0.00 0.000001 1 1 arch_prctl
|
||||||
|
0.00 0.000001 1 1 set_tid_address
|
||||||
|
0.00 0.000001 1 1 set_robust_list
|
||||||
|
0.00 0.000001 1 1 prlimit64
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
100.00 1.971639 85 1 total
|
||||||
|
```
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ strace -c ./peterson
|
||||||
|
program running time: 4.891933
|
||||||
|
author: 柯劲帆
|
||||||
|
% time seconds usecs/call calls errors syscall
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
0.00 0.000000 0 5 read
|
||||||
|
0.00 0.000000 0 2 write
|
||||||
|
0.00 0.000000 0 6 close
|
||||||
|
0.00 0.000000 0 7 fstat
|
||||||
|
0.00 0.000000 0 29 mmap
|
||||||
|
0.00 0.000000 0 12 mprotect
|
||||||
|
0.00 0.000000 0 1 munmap
|
||||||
|
0.00 0.000000 0 3 brk
|
||||||
|
0.00 0.000000 0 2 rt_sigaction
|
||||||
|
0.00 0.000000 0 1 rt_sigprocmask
|
||||||
|
0.00 0.000000 0 1 1 access
|
||||||
|
0.00 0.000000 0 2 clone
|
||||||
|
0.00 0.000000 0 1 execve
|
||||||
|
0.00 0.000000 0 1 arch_prctl
|
||||||
|
0.00 0.000000 0 1 futex
|
||||||
|
0.00 0.000000 0 1 set_tid_address
|
||||||
|
0.00 0.000000 0 2 clock_gettime
|
||||||
|
0.00 0.000000 0 6 openat
|
||||||
|
0.00 0.000000 0 1 set_robust_list
|
||||||
|
0.00 0.000000 0 1 prlimit64
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
100.00 0.000000 85 1 total
|
||||||
|
```
|
||||||
|
|
||||||
|
使用taskset命令,将linux_sync程序的线程绑定到7号CPU上运行,并使用strace工具进行监视系统调用情况。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ strace -c taskset -c 7 ./linux_sync
|
||||||
|
program running time: 0.451617
|
||||||
|
author: 柯劲帆
|
||||||
|
% time seconds usecs/call calls errors syscall
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
81.46 0.002184 1092 2 futex
|
||||||
|
9.85 0.000264 132 2 clone
|
||||||
|
3.25 0.000087 2 37 mmap
|
||||||
|
1.49 0.000040 2 16 mprotect
|
||||||
|
0.82 0.000022 2 9 openat
|
||||||
|
0.63 0.000017 17 1 sched_setaffinity
|
||||||
|
0.48 0.000013 6 2 munmap
|
||||||
|
0.34 0.000009 1 6 read
|
||||||
|
0.34 0.000009 0 10 fstat
|
||||||
|
0.30 0.000008 0 9 close
|
||||||
|
0.30 0.000008 1 6 brk
|
||||||
|
0.22 0.000006 3 2 2 access
|
||||||
|
0.11 0.000003 1 2 execve
|
||||||
|
0.07 0.000002 1 2 rt_sigaction
|
||||||
|
0.07 0.000002 1 2 arch_prctl
|
||||||
|
0.07 0.000002 2 1 sched_getaffinity
|
||||||
|
0.04 0.000001 1 1 rt_sigprocmask
|
||||||
|
0.04 0.000001 1 1 set_tid_address
|
||||||
|
0.04 0.000001 0 2 clock_gettime
|
||||||
|
0.04 0.000001 1 1 set_robust_list
|
||||||
|
0.04 0.000001 1 1 prlimit64
|
||||||
|
0.00 0.000000 0 2 write
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
100.00 0.002681 117 2 total
|
||||||
|
```
|
||||||
|
|
||||||
|
发现linux_sync程序运行速度非常快,用时接近无绑定CPU运行时间的$10\%$。比较strace显示的系统调用用时,发现futex用时减少显著。
|
||||||
|
|
||||||
|
说明在futex调度多个CPU的过程中产生了大量的时间开销。
|
||||||
|
|
||||||
|
同理使用taskset命令,将peterson程序的线程绑定到7号CPU上运行,并使用strace工具进行监视系统调用情况。
|
||||||
|
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ strace -c taskset -c 7 ./peterson
|
||||||
|
^Cstrace: Process 26667 detached
|
||||||
|
% time seconds usecs/call calls errors syscall
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
0.00 0.000000 0 6 read
|
||||||
|
0.00 0.000000 0 9 close
|
||||||
|
0.00 0.000000 0 9 fstat
|
||||||
|
0.00 0.000000 0 37 mmap
|
||||||
|
0.00 0.000000 0 16 mprotect
|
||||||
|
0.00 0.000000 0 2 munmap
|
||||||
|
0.00 0.000000 0 6 brk
|
||||||
|
0.00 0.000000 0 2 rt_sigaction
|
||||||
|
0.00 0.000000 0 1 rt_sigprocmask
|
||||||
|
0.00 0.000000 0 2 2 access
|
||||||
|
0.00 0.000000 0 2 clone
|
||||||
|
0.00 0.000000 0 2 execve
|
||||||
|
0.00 0.000000 0 2 arch_prctl
|
||||||
|
0.00 0.000000 0 1 1 futex
|
||||||
|
0.00 0.000000 0 1 sched_setaffinity
|
||||||
|
0.00 0.000000 0 1 sched_getaffinity
|
||||||
|
0.00 0.000000 0 1 set_tid_address
|
||||||
|
0.00 0.000000 0 1 clock_gettime
|
||||||
|
0.00 0.000000 0 9 openat
|
||||||
|
0.00 0.000000 0 1 set_robust_list
|
||||||
|
0.00 0.000000 0 1 prlimit64
|
||||||
|
------ ----------- ----------- --------- --------- ----------------
|
||||||
|
100.00 0.000000 112 3 total
|
||||||
|
```
|
||||||
|
|
||||||
|
发现在单颗CPU上运行的peterson程序运行非常缓慢;futex只被调用1次且用时忽略不计。
|
||||||
|
|
||||||
|
将该程序提前结束。
|
||||||
|
|
||||||
|
减小`LOOP_NUM`的大小,观察导致单核中peterson程序运行缓慢的原因。
|
||||||
|
|
||||||
|
在源代码中修改`LOOP_NUM`的大小。
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// const int LOOP_NUM = 10000000;
|
||||||
|
const int LOOP_NUM = 1000;
|
||||||
|
```
|
||||||
|
|
||||||
|
编译并运行。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ g++ ./peterson.cpp -o ./peterson -pthread && taskset -c 7 ./peterson
|
||||||
|
program running time: 0.000046
|
||||||
|
author: 柯劲帆
|
||||||
|
```
|
||||||
|
|
||||||
|
程序正常地快速运行完毕了。
|
||||||
|
|
||||||
|
不断调整循环次数`LOOP_NUM`的大小,发现当`LOOP_NUM`为10^3的数量级或以下时,程序正常快速运行并结束;当`LOOP_NUM`为10^5的数量级以上时,程序运行极为缓慢;`LOOP_NUM`在10^3和10^5的数量级之间时,程序有时快速运行并结束,有时运行非常慢,且受到是否使用strace工具监视的影响。
|
||||||
|
|
||||||
|
上述实验结果记录如下:
|
||||||
|
|
||||||
|
| `LOOP_NUM` | 10^2 | 10^3 | 10^4 | 10^5 | 10^6 | 10^7 |
|
||||||
|
| :------------------------: | :-----------: | :-----------: | :-----------: | :-----------: | :---------: | :---------: |
|
||||||
|
| 直接运行程序用时 | $0.000027$ 秒 | $0.000032$ 秒 | $0.000081$ 秒 | $0.001459$ 秒 | 超过$1$分钟 | 超过$1$分钟 |
|
||||||
|
| 使用strace工具监视程序用时 | $0.000037$ 秒 | $0.000051$ 秒 | $0.000040$ 秒 | 超过$1$分钟 | 超过$1$分钟 | 超过$1$分钟 |
|
||||||
|
|
||||||
|
可以看出,循环次数的数量级的增加导致了运行时间的大量非线性增加,由此猜测是线程运行时间的长短导致了操作系统采用了不同的并发执行策略,导致了总的程序执行时间产生了非线性变化。
|
||||||
|
|
||||||
|
因此我又做了如下实验:
|
||||||
|
|
||||||
|
修改代码,在peterson程序中每个临界区结束时,打印输出线程编号和`nLoop`值。分别设置`LOOP_NUM`为10^3和10^7,编译和运行peterson程序。(限于篇幅,此处省略程序输出的展示,仅用文字说明结果)
|
||||||
|
|
||||||
|
观察发现,当`LOOP_NUM`为10^3时,两个线程并不是交错执行的,而是当transA线程循环结束时,transB线程才开始循环,相当于串行执行;但是当`LOOP_NUM`为10^7时,首先transA线程循环了1329次后,transB线程才开始循环,接下来两个线程交错执行,如下是截取的部分输出:
|
||||||
|
|
||||||
|
(每行两个数。第一个数为1表示该行由transA输出,第一个数为2表示该行由transB输出;第二个数表示该行是在对应线程的第几个循环输出的。)
|
||||||
|
|
||||||
|
```txt
|
||||||
|
1 1326
|
||||||
|
1 1327
|
||||||
|
1 1328
|
||||||
|
1 1329
|
||||||
|
2 1
|
||||||
|
1 1330
|
||||||
|
2 2
|
||||||
|
1 1331
|
||||||
|
2 3
|
||||||
|
1 1332
|
||||||
|
2 4
|
||||||
|
1 1333
|
||||||
|
```
|
||||||
|
|
||||||
|
说明影响单颗CPU上peterson程序运行时间大幅度变化的原因是:
|
||||||
|
|
||||||
|
- 单个线程运行时间较短时(如`LOOP_NUM`为10^3),操作系统倾向于让线程串行计算,减少了切换开销;
|
||||||
|
- 当单个线程独占CPU的运行时间达到一定长度时,操作系统会将另一个线程插入,让两个线程并发运行。因此当线程运行时间较长时(如`LOOP_NUM`为10^7),在第一个线程运行一段时间后,另一个线程也开始运行,两个线程开始频繁争抢CPU时间片,切换开销变大,导致运行速度急剧下降;
|
||||||
|
- strace工具会增加计算开销,影响操作系统的决策。在`LOOP_NUM`为10^4到10^5的数量级时,当该CPU上的运行任务较多,串行运行的线程可能提前开始与其他线程并行运行,导致运行速度急剧下降。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 3. 实验分析
|
||||||
|
|
||||||
|
### 3.1. none_sync算法错误原因分析
|
||||||
|
|
||||||
|
分析修改了输出信息的none_sync_1.cpp编译的程序,作出时序执行图:
|
||||||
|
|
||||||
|
<img src="graph.drawio.svg" alt="graph.drawio" style="zoom: 90%;" />
|
||||||
|
|
||||||
|
出错的原因是:
|
||||||
|
|
||||||
|
**在无同步控制的情况下,当两个线程同时执行转账操作时,会出现数据竞争的问题。**
|
||||||
|
|
||||||
|
**具体来说,transA线程读取了账户余额,此时transB线程也读取了相同的账户余额,然后两线程基于读取的余额做计算,最后写入结果。这会导致计算错误,总额不再相等。**
|
||||||
|
|
||||||
|
### 3.2. 后两种算法正确的原因分析
|
||||||
|
|
||||||
|
#### 3.2.1. Linux操作系统同步机制正确的原因
|
||||||
|
|
||||||
|
**语句`pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;`创建的互斥锁保护了共享资源的访问,防止多线程竞争。**
|
||||||
|
|
||||||
|
当transA线程即将进入临界区时,`pthread_mutex_lock(&mutex);`语句调用系统接口锁定互斥锁,保护临界区,直至临界区执行完毕。在这个过程中,transB线程都无法进入临界区,从而保护了共享资源nAccount1和nAccount2变量在transA线程运行的过程中不会被transB修改。同理,transB线程锁定互斥锁后,transA无法进入临界区。
|
||||||
|
|
||||||
|
#### 3.2.2. Peterson算法正确的原因
|
||||||
|
|
||||||
|
将**进入临界区前**的并行执行情况枚举如下(假设当前没有线程执行临界区,flag都为false):
|
||||||
|
|
||||||
|
| 步骤1 | 步骤2 | 步骤3 | 步骤4 | 步骤5 | 步骤6 | 步骤7 | 进入 |
|
||||||
|
| :-----------------: | :-------------------: | :--------------------: | :------------------: | :------------------: | :-------------------: | :-------------------: | :----: |
|
||||||
|
| `A` flag[0] = _true | `A` turn = 1 | `A` while () --> false | | | | | transA |
|
||||||
|
| `A` flag[0] = _true | `A` turn = 1 | `B` flag[1] = _true | `B` turn = 0 | `B` while() --> true | `A` while() --> false | | transA |
|
||||||
|
| `A` flag[0] = _true | `B` flag[1] = _true | `B` turn = 0 | `B` while() --> true | `A` turn = 1 | `A` while() --> true | `B` while() --> false | transB |
|
||||||
|
| `A` flag[0] = _true | `B` flag[1] = _true | `A` turn = 1 | `A` while() --> true | `B` turn = 0 | `B` while() --> true | `A` while() --> false | transA |
|
||||||
|
| `A` flag[0] = _true | `B` turn = 0 | `B` while() --> true | `A` turn = 1 | `A` while() --> true | `B` while() --> false | | transB |
|
||||||
|
| `A` flag[0] = _true | `B` while() --> false | | | | | | transB |
|
||||||
|
|
||||||
|
以上是transA先执行第1行do-while代码的大部分情况枚举(由对称性,transB先执行第1行do-while代码的情况同理)。
|
||||||
|
|
||||||
|
当任意一个线程(如transA)**在临界区内执行时**,该线程(如transA)对应的flag都为true,另外一个线程(如transB)在判断是否要等待的while语句前,turn都会被赋值为正在执行临界区的线程(如transA)的编号。因此未进入临界区的线程(如transB)会陷入while循环等待。
|
||||||
|
|
||||||
|
显然,peterson算法的逻辑可以使得在同一时刻执行临界区的线程数不超过1个,且不会发生所有线程都在while等待的情况。
|
||||||
|
|
||||||
|
### 3.3. Peterson 算法或Linux操作系统同步机制出现问题的原因分析
|
||||||
|
|
||||||
|
Peterson 算法或Linux操作系统同步机制的代码不会导致$\rm{nAccount1} + \rm{nAccount2} \ne 0$,因此不加循环变量的判别不会跳出循环,导致程序死循环。
|
||||||
|
|
||||||
|
因此将循环设置为`nLoop < 1000000`,并用`if (nAccount1 + nAccount2 != 0) break;`语句实现原循环条件中的判别功能。
|
||||||
|
|
||||||
|
### 3.4. 两种同步机制的效率比较
|
||||||
|
|
||||||
|
从**运行机制**上来看,Linux操作系统同步机制比Peterson算法相对效率更高。
|
||||||
|
|
||||||
|
- Peterson算法通过旗标变量和轮转变量实现互斥,需要线程自己判断是否获得访问权限,需要更多的用户态运算来实现同步。
|
||||||
|
|
||||||
|
- 操作系统同步机制通过内核级锁实现互斥,由操作系统直接管理同步访问,线程直接获取和释放访问权限,减少了用户态和内核态之间的切换,也不需要线程自己实现同步逻辑,效率更高。
|
||||||
|
|
||||||
|
但是从实验中的**实际运行**时间上看,Peterson算法相对Linux操作系统同步机制效率更高。
|
||||||
|
|
||||||
|
下面通过分析实验过程的现象比较两种同步机制的效率:
|
||||||
|
|
||||||
|
1. 在使用strace工具观察linux_sync程序和peterson程序的系统调用情况的过程中,分析发现耗时最多的系统调用是futex。linux_sync程序调用了两次futex,总共用时较多,而peterson程序只调用了一次futex,用时忽略不计。
|
||||||
|
|
||||||
|
查阅资料<sup>[[1]](https://linux.die.net/man/2/futex)</sup>可知,futex用于等待给定地址的值发生更改,并为唤醒在特定地址上等待的任何线程提供了一个方法,用于实现共享内存中锁的争用情况。
|
||||||
|
|
||||||
|
在linux_sync程序中,第二个线程执行前访问了futex变量,检测到第一个线程被锁定了,因此进入等待状态,并在第一个线程完成后被唤醒。这样的机制使得linux_sync程序实现内核级锁实现互斥,减少用户态和内核态之间的切换,效率更高。而peterson程序只调用了一次futex,在该项系统调用内并行完成了两个线程。
|
||||||
|
|
||||||
|
2. 在将线程绑定到单个CPU上运行的实验中,发现linux_sync程序运行速度非常快,用时接近无绑定CPU运行时间的$10\%$;但是peterson程序运行非常缓慢。
|
||||||
|
|
||||||
|
- linux_sync程序:在多核并行运行时,linux_sync程序需要通过系统调用futex影响CPU的调度,这个调度过程消耗了大量的时间,但是当绑定单个CPU之后这个调度过程被简化了,因此运行时间大大减少。
|
||||||
|
|
||||||
|
- peterson程序:当循环次数到10^3量级以上时,操作系统会让两个线程交替执行,线程切换开销较大,导致绑定单个CPU之后,peterson程序运行非常缓慢;但是不绑定CPU,即使有CPU调度的开销,多核并发的贡献能抵消调度开销,大大减少peterson程序运行的时间。
|
||||||
|
|
||||||
|
3. 直接在命令行运行linux_sync程序和peterson程序,多次运行,通过比较运行时间反映两种算法或机制的运行效率。从实际运行时间上看,peterson算法相对linux操作系统同步机制效率更高。
|
||||||
|
|
||||||
|
根据以上现象和资料,总结出以下的原因导致Peterson算法程序的运行时间比linux_sync程序的运行时间短:
|
||||||
|
|
||||||
|
- peterson程序中没有使用系统调用,核心运算也非常简单,所以系统调度更具灵活性,有助于多核并发,弥补了CPU调度开销和线程切换开销;
|
||||||
|
- linux_sync程序进行了系统调用,存在大量CPU的调度时间开销。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 5. 问题与讨论
|
||||||
|
|
||||||
|
### 5.1. 编译问题
|
||||||
|
|
||||||
|
使用g++编译3份代码时,需要加`-pthread`参数,如下。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ g++ ./none_sync.cpp -o ./none_sync -pthread
|
||||||
|
```
|
||||||
|
|
||||||
|
否则,
|
||||||
|
|
||||||
|
```shell
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ g++ ./none_sync.cpp -o ./none_sync
|
||||||
|
/usr/bin/ld: /tmp/ccrfomkX.o: in function `main':
|
||||||
|
none_sync.cpp:(.text+0x18e): undefined reference to `pthread_create'
|
||||||
|
/usr/bin/ld: none_sync.cpp:(.text+0x1a9): undefined reference to `pthread_create'
|
||||||
|
/usr/bin/ld: none_sync.cpp:(.text+0x1ba): undefined reference to `pthread_join'
|
||||||
|
/usr/bin/ld: none_sync.cpp:(.text+0x1cb): undefined reference to `pthread_join'
|
||||||
|
collect2: error: ld returned 1 exit status
|
||||||
|
```
|
||||||
|
|
||||||
|
这可能是由于操作系统所带的g++ (Uos 8.3.0.3-3+rebuild) 8.3.0版本特性导致的。我在g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0版本上并未发现不加`-pthread`参数会报错。
|
||||||
|
|
||||||
|
`-pthread` 参数是告诉g++编译器链接POSIX线程库的选项。POSIX线程库是一种用于多线程编程的标准库,也被称为pthreads(POSIX Threads)。它提供了创建、管理和同步线程的函数和数据结构<sup>[[2]]([pthreads - Wikipedia](https://en.wikipedia.org/wiki/Pthreads))</sup>。当在代码中使用多线程功能,如 `pthread_create` 和 `pthread_join` 时,需要链接 pthreads 库,以便编译器能够找到这些函数的定义并正确连接它们到可执行文件中。如果不加 `-pthread` 参数,编译器可能会产生错误消息,因为它无法找到对应的线程函数定义。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 6. 实验结论
|
||||||
|
|
||||||
|
- 不加线程同步机制的并行线程在访问共享资源时容易产生数据竞争,会导致运算错误等一系列问题。开发者需要在程序开发中注意线程并行同步机制的问题,注意避免数据竞争,保护共享资源。
|
||||||
|
- 多线程并发过程中的主要额外时间开销是进程切换开销和CPU调度开销,开发者需要将这两个开销与多线程并行计算和多核并行计算的效率优势进行权衡。
|
||||||
|
- 不同的线程同步机制在实现上有区别,如Peterson算法主要依靠程序逻辑实现,而Linux内核则是通过系统调用实现互斥机制。同一同步机制在不同条件下(如不同程序、不同系统)效率也可能有所不同,因为这些条件既会影响线程切换和CPU切换的开销,也会影响计算速度等别的因素。选择合适的机制可以提高效率。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 7. 附录
|
||||||
|
|
||||||
|
### 7.1. none_sync_1程序的完整输出
|
||||||
|
|
||||||
|
|
||||||
|
```txt
|
||||||
|
(base) kejingfan@KJF-Huawei-PC:~/code$ ./linux_sync
|
||||||
|
[transB:0] nTemp1 = 0
|
||||||
|
[transB:0] nTemp2 = 0
|
||||||
|
[transB:0] nAccount1 = 0 + 3 = 3
|
||||||
|
[transB:0] nAccount2 = 0 - 3 = -3
|
||||||
|
[transB:1] nTemp1 = 3
|
||||||
|
[transB:1] nTemp2 = -3
|
||||||
|
[transB:1] nAccount1 = 3 + 6 = 9
|
||||||
|
[transB:1] nAccount2 = -3 - 6 = -9
|
||||||
|
[transB:2] nTemp1 = 9
|
||||||
|
[transB:2] nTemp2 = -9
|
||||||
|
[transB:2] nAccount1 = 9 + 7 = 16
|
||||||
|
[transB:2] nAccount2 = -9 - 7 = -16
|
||||||
|
[transB:3] nTemp1 = 16
|
||||||
|
[transB:3] nTemp2 = -16
|
||||||
|
[transA:0] nTemp1 = 16
|
||||||
|
[transA:0] nTemp2 = -16
|
||||||
|
[transA:0] nAccount1 = 16 + 7793 = 7809
|
||||||
|
[transA:0] nAccount2 = -16 - 7793 = -7809
|
||||||
|
[transA:1] nTemp1 = 7809
|
||||||
|
[transA:1] nTemp2 = -7809
|
||||||
|
[transA:1] nAccount1 = 7809 + 8335 = 16144
|
||||||
|
[transA:1] nAccount2 = -7809 - 8335 = -16144
|
||||||
|
[transA:2] nTemp1 = 16144
|
||||||
|
[transA:2] nTemp2 = -16144
|
||||||
|
[transA:2] nAccount1 = 16144 + 5386 = 21530
|
||||||
|
[transA:2] nAccount2 = -16144 - 5386 = -21530
|
||||||
|
[transA:3] nTemp1 = 21530
|
||||||
|
[transA:3] nTemp2 = -21530
|
||||||
|
[transA:3] nAccount1 = 21530 + 492 = 22022
|
||||||
|
[transA:3] nAccount2 = -21530 - 492 = -22022
|
||||||
|
[transA:4] nTemp1 = 22022
|
||||||
|
[transA:4] nTemp2 = -22022
|
||||||
|
[transA:4] nAccount1 = 22022 + 6649 = 28671
|
||||||
|
[transA:4] nAccount2 = -22022 - 6649 = -28671
|
||||||
|
[transA:5] nTemp1 = 28671
|
||||||
|
[transA:5] nTemp2 = -28671
|
||||||
|
[transA:5] nAccount1 = 28671 + 1421 = 30092
|
||||||
|
[transA:5] nAccount2 = -28671 - 1421 = -30092
|
||||||
|
[transA:6] nTemp1 = 30092
|
||||||
|
[transA:6] nTemp2 = -30092
|
||||||
|
[transA:6] nAccount1 = 30092 + 2362 = 32454
|
||||||
|
[transA:6] nAccount2 = -30092 - 2362 = -32454
|
||||||
|
[transA:7] nTemp1 = 32454
|
||||||
|
[transA:7] nTemp2 = -32454
|
||||||
|
[transA:7] nAccount1 = 32454 + 27 = 32481
|
||||||
|
[transA:7] nAccount2 = -32454 - 27 = -32481
|
||||||
|
[transA:8] nTemp1 = 32481
|
||||||
|
[transA:8] nTemp2 = -32481
|
||||||
|
[transA:8] nAccount1 = 32481 + 8690 = 41171
|
||||||
|
[transA:8] nAccount2 = -32481 - 8690 = -41171
|
||||||
|
[transB:3] nAccount1 = 16 + 5 = 21
|
||||||
|
[transB:3] nAccount2 = -16 - 5 = -21
|
||||||
|
[transA:9] nTemp1 = 41171
|
||||||
|
[transA:9] nTemp2 = -21
|
||||||
|
[transA:9] nAccount1 = 41171 + 59 = 41230
|
||||||
|
[transA:9] nAccount2 = -21 - 59 = -80
|
||||||
|
error
|
||||||
|
[transA] nTemp1=41171, nTemp2=-21, nRandom=59, nTemp1+nRandom=41230, nTemp2-nRandom=-80, nAccount1=41230, nAccount2=-80
|
||||||
|
error
|
||||||
|
[transB] nTemp1=16, nTemp2=-16, nRandom=5, nTemp1+nRandom=21, nTemp2-nRandom=-21, nAccount1=41230, nAccount2=-80
|
||||||
|
program running time: 0.000237
|
||||||
|
author: 柯劲帆
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2. 参考资料
|
||||||
|
|
||||||
|
[[1]](https://linux.die.net/man/2/futex) The futex() system call provides a method for a program to wait for a value at a given address to change, and a method to wake up anyone waiting on a particular address (while the addresses for the same memory in separate processes may not be equal, the kernel maps them internally so the same memory mapped in different locations will correspond for futex() calls). This system call is typically used to implement the contended case of a lock in shared memory.
|
||||||
|
|
||||||
|
[[2]]([pthreads - Wikipedia](https://en.wikipedia.org/wiki/Pthreads)) In computing, POSIX Threads, commonly known as pthreads, is an execution model that exists independently from a programming language, as well as a parallel execution model. It allows a program to control multiple different flows of work that overlap in time. Each flow of work is referred to as a thread, and creation and control over these flows is achieved by making calls to the POSIX Threads API.
|
BIN
Lab/Lab1/material/21281280-柯劲帆-第1次实验.pdf
Normal file
BIN
Lab/Lab1/material/21281280-柯劲帆-第1次实验.pdf
Normal file
Binary file not shown.
386
Lab/Lab1/material/graph.drawio
Normal file
386
Lab/Lab1/material/graph.drawio
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
<mxfile host="Electron" modified="2023-09-15T17:26:03.733Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.7.5 Chrome/114.0.5735.289 Electron/25.8.1 Safari/537.36" etag="pPNBxq_dEBynq3NRsfst" version="21.7.5" type="device">
|
||||||
|
<diagram name="第 1 页" id="sjCZumlual-5YgjK0dVd">
|
||||||
|
<mxGraphModel dx="1418" dy="1220" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-64" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="1020" y="-20" width="310" height="1350" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-63" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="710" y="-20" width="310" height="1350" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-62" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="380" y="-20" width="310" height="1350" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-61" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="70" y="-20" width="310" height="1350" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-51" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="950" width="140" height="1310" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="VQuQIdw22lLKVOqoggoi-1" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="310" width="140" height="1310" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-14" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-1" target="OhlrbkmSlsnOyg6t7Ixe-3" edge="1">
|
||||||
|
<mxGeometry x="-0.25" y="40" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-1" value="transB线程开始" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="510" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-3" value="[0]&nbsp;nTemp1 = nAccount1;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="460" y="80" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-4" value="nTemp1 = 0" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-3" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-7" value="transA线程开始" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="130" y="800" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-47" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-12" target="OhlrbkmSlsnOyg6t7Ixe-45" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-12" value="[0]&nbsp;nTemp1 = nAccount1;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="80" y="880" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-13" value="nTemp1 = 16" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-12" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-15" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-7" target="OhlrbkmSlsnOyg6t7Ixe-12" edge="1">
|
||||||
|
<mxGeometry x="-0.25" y="40" relative="1" as="geometry">
|
||||||
|
<mxPoint x="240" y="100" as="sourcePoint" />
|
||||||
|
<mxPoint x="240" y="180" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-16" value="[0]&nbsp;nTemp2 = nAccount2;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="460" y="180" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-17" value="nTemp2 = 0" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-16" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-19" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-3" target="OhlrbkmSlsnOyg6t7Ixe-16" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="790" y="40" as="sourcePoint" />
|
||||||
|
<mxPoint x="630" y="90" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-20" value="[0]&nbsp;nAccount1 = nTemp1 + nRandom;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="460" y="280" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-21" value="nTemp1 = 0" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-20" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-77" value="nAccount1 = 0 + 3 = 3" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-20" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-22" value="[0]&nbsp;nAccount2 = nTemp2 - nRandom;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="460" y="410" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-23" value="nTemp2 = 0" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-22" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-78" value="nAccount2 = 0 - 3 = -3" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-22" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-20" target="OhlrbkmSlsnOyg6t7Ixe-22" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="790" y="240" as="sourcePoint" />
|
||||||
|
<mxPoint x="630" y="290" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-25" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-16" target="OhlrbkmSlsnOyg6t7Ixe-20" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="450" y="260" as="sourcePoint" />
|
||||||
|
<mxPoint x="630" y="190" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-26" value="[3]&nbsp;nTemp1 = nAccount1;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="460" y="640" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-27" value="nTemp1 = 16" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-26" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-70" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;dashed=1;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-28" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="570" y="1310" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-28" value="[3]&nbsp;nTemp2 = nAccount2;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="460" y="740" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-29" value="nTemp2 = -16" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-28" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-30" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-26" target="OhlrbkmSlsnOyg6t7Ixe-28" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="790" y="680" as="sourcePoint" />
|
||||||
|
<mxPoint x="620" y="740" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-31" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-22" target="OhlrbkmSlsnOyg6t7Ixe-32" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="630" y="490" as="sourcePoint" />
|
||||||
|
<mxPoint x="630" y="530" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-32" value="[1]&nbsp; ... [2]" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="460" y="540" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-34" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-32" target="OhlrbkmSlsnOyg6t7Ixe-26" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="590" y="720" as="sourcePoint" />
|
||||||
|
<mxPoint x="590" y="760" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-36" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-35" target="OhlrbkmSlsnOyg6t7Ixe-3" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-35" value="nAccount1 = 0<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = 0</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="330" y="40" width="100" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-38" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-37" target="OhlrbkmSlsnOyg6t7Ixe-16" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-37" value="nAccount1 = 0<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = 0</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="330" y="140" width="100" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-39" target="OhlrbkmSlsnOyg6t7Ixe-26" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-39" value="nAccount1 = 16<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = -16</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="320" y="600" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-119" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-41" target="OhlrbkmSlsnOyg6t7Ixe-28" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-41" value="nAccount1 = 16<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = -16</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="320" y="700" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-79" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-43" target="OhlrbkmSlsnOyg6t7Ixe-45" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-43" value="nAccount1 = 16<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = -16</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="320" y="940" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-57" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-45" target="dmcueJ9po_xcNufoxRre-54" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="180" y="1080" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-45" value="[0]&nbsp;nTemp2 = nAccount2;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="80" y="980" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-46" value="nTemp2 = -16" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="OhlrbkmSlsnOyg6t7Ixe-45" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-81" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="OhlrbkmSlsnOyg6t7Ixe-48" target="OhlrbkmSlsnOyg6t7Ixe-12" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="OhlrbkmSlsnOyg6t7Ixe-48" value="nAccount1 = 16<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = -16</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="320" y="840" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="VQuQIdw22lLKVOqoggoi-3" value="<h1>共享资源<br></h1>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="325" y="-10" width="110" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-4" target="dmcueJ9po_xcNufoxRre-21" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-4" value="nAccount1 = 41171<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = -41171</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="960" y="130" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-9" target="dmcueJ9po_xcNufoxRre-21" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-9" value="[8]&nbsp;nAccount2 = nTemp2 - nRandom;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="720" y="40" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-10" value="nTemp2 = -32481" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-9" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-11" value="nAccount2 = -32481 - 8690 = -41171" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-9" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-12" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;dashed=1;" parent="1" target="dmcueJ9po_xcNufoxRre-9" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="830" as="sourcePoint" />
|
||||||
|
<mxPoint x="1410" y="-80" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-13" value="[3]&nbsp;nAccount1 = nTemp1 + nRandom;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="1100" y="270" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-14" value="nTemp1 = 16" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-13" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-15" value="nAccount1 = 16 + 5 = 21" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-13" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-17" target="dmcueJ9po_xcNufoxRre-42" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-17" value="[3]&nbsp;nAccount2 = nTemp2 - nRandom;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="1100" y="400" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-18" value="nTemp2 = -16" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-17" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-19" value="nAccount2 = -16 - 5 = -21" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-17" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-20" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-13" target="dmcueJ9po_xcNufoxRre-17" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="1390" y="170" as="sourcePoint" />
|
||||||
|
<mxPoint x="1230" y="220" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-21" value="[9]&nbsp;nTemp1 = nAccount1;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="720" y="170" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-22" value="nTemp1 = 41171" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-21" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-24" target="dmcueJ9po_xcNufoxRre-29" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-24" value="[9]&nbsp;nTemp2 = nAccount2;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="720" y="530" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-25" value="nTemp2 = -21" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-24" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-26" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-21" target="dmcueJ9po_xcNufoxRre-24" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="1010" y="230" as="sourcePoint" />
|
||||||
|
<mxPoint x="850" y="280" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-27" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-28" target="dmcueJ9po_xcNufoxRre-24" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-28" value="nAccount1 = 21<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = -21</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="960" y="490" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-29" value="[8]&nbsp;nAccount1 = nTemp1 + nRandom;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="720" y="630" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-30" value="nTemp1 = 41171" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-29" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-31" value="nAccount1 = 41171 + 59 = 41230" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-29" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-33" target="dmcueJ9po_xcNufoxRre-38" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-33" value="[8]&nbsp;nAccount2 = nTemp2 - nRandom;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="720" y="760" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-34" value="nTemp2 = -21" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-33" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-35" value="nAccount2 = -21 - 59 = -80" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-33" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-36" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-29" target="dmcueJ9po_xcNufoxRre-33" edge="1">
|
||||||
|
<mxGeometry y="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="1570" y="590" as="sourcePoint" />
|
||||||
|
<mxPoint x="1410" y="640" as="targetPoint" />
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-37" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-38" target="dmcueJ9po_xcNufoxRre-47" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-38" value="[8]&nbsp;nAccount1 + nAccount2 != 0" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="720" y="890" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-40" value="printf(nAccount1) --&gt; 41230" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-38" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-39" value="printf(nAccount2) --&gt; -80" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-38" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-41" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-42" target="dmcueJ9po_xcNufoxRre-48" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-42" value="[3]&nbsp;nAccount1 + nAccount2 != 0" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="1100" y="1100" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-44" value="printf(nAccount1) --&gt; 41230" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-42" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-43" value="printf(nAccount2) --&gt; -80" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-42" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-45" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-46" target="dmcueJ9po_xcNufoxRre-38" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-46" value="nAccount1 = 41230<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = -80</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="960" y="850" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-47" value="transA线程结束" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="770" y="1020" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-48" value="transB线程结束" style="ellipse;whiteSpace=wrap;html=1;fillColor=default;strokeColor=default;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="1150" y="1230" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-49" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-50" target="dmcueJ9po_xcNufoxRre-42" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-50" value="nAccount1 = 41230<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">nAccount2 = -80</span>" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="960" y="1060" width="120" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-52" value="<h1>共享资源<br></h1>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="965" y="-10" width="110" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-53" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="dmcueJ9po_xcNufoxRre-54" target="dmcueJ9po_xcNufoxRre-55" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="180" y="1180" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-54" value="[1]&nbsp; ... [8]" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="80" y="1080" width="220" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-55" value="[8]&nbsp;nAccount1 = nTemp1 + nRandom;" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="80" y="1180" width="220" height="90" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-56" value="nTemp1 = 32481" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-55" vertex="1">
|
||||||
|
<mxGeometry y="30" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-57" value="nAccount1 = 32481 + 8690 = 41171" style="text;strokeColor=#6c8ebf;fillColor=#dae8fc;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="dmcueJ9po_xcNufoxRre-55" vertex="1">
|
||||||
|
<mxGeometry y="60" width="220" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-58" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;dashed=1;" parent="1" source="dmcueJ9po_xcNufoxRre-55" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="680" y="1420" as="sourcePoint" />
|
||||||
|
<mxPoint x="190" y="1310" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-59" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" target="dmcueJ9po_xcNufoxRre-13" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="1210" as="sourcePoint" />
|
||||||
|
<mxPoint x="1450" y="670" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="dmcueJ9po_xcNufoxRre-60" value="" style="endArrow=none;dashed=1;html=1;rounded=0;fillColor=#0050ef;strokeColor=#001DBC;" parent="1" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="700" y="1330" as="sourcePoint" />
|
||||||
|
<mxPoint x="700" y="-20" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
BIN
Lab/Lab1/material/graph.drawio.png
Normal file
BIN
Lab/Lab1/material/graph.drawio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 214 KiB |
4
Lab/Lab1/material/graph.drawio.svg
Normal file
4
Lab/Lab1/material/graph.drawio.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 85 KiB |
BIN
Lab/Lab1/material/graph.jpg
Normal file
BIN
Lab/Lab1/material/graph.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 170 KiB |
BIN
Lab/Lab1/第一次操作系统实验要求.docx
Normal file
BIN
Lab/Lab1/第一次操作系统实验要求.docx
Normal file
Binary file not shown.
BIN
Lab/Lab2/21281280-柯劲帆-第2次实验.pdf
Normal file
BIN
Lab/Lab2/21281280-柯劲帆-第2次实验.pdf
Normal file
Binary file not shown.
BIN
Lab/Lab2/requirements/第2次实验-典型同步问题算法验证实验.docx
Normal file
BIN
Lab/Lab2/requirements/第2次实验-典型同步问题算法验证实验.docx
Normal file
Binary file not shown.
BIN
Lab/Lab2/requirements/第2次实验-典型同步问题算法验证实验.pdf
Normal file
BIN
Lab/Lab2/requirements/第2次实验-典型同步问题算法验证实验.pdf
Normal file
Binary file not shown.
1565
Lab/Lab2/source/21281280-柯劲帆-第2次实验.md
Normal file
1565
Lab/Lab2/source/21281280-柯劲帆-第2次实验.md
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Lab/Lab2/source/21281280-柯劲帆-第2次实验.pdf
Normal file
BIN
Lab/Lab2/source/21281280-柯劲帆-第2次实验.pdf
Normal file
Binary file not shown.
BIN
Lab/Lab3/21281280-柯劲帆-第3次实验.pdf
Normal file
BIN
Lab/Lab3/21281280-柯劲帆-第3次实验.pdf
Normal file
Binary file not shown.
BIN
Lab/Lab3/requirements/Linux内核完全注释.pdf
Normal file
BIN
Lab/Lab3/requirements/Linux内核完全注释.pdf
Normal file
Binary file not shown.
BIN
Lab/Lab3/requirements/bochs编译linux-0.11.docx
Normal file
BIN
Lab/Lab3/requirements/bochs编译linux-0.11.docx
Normal file
Binary file not shown.
BIN
Lab/Lab3/requirements/第3次实验-进程控制实现机制.docx
Normal file
BIN
Lab/Lab3/requirements/第3次实验-进程控制实现机制.docx
Normal file
Binary file not shown.
BIN
Lab/Lab3/requirements/第三次实验的示例指导.docx
Normal file
BIN
Lab/Lab3/requirements/第三次实验的示例指导.docx
Normal file
Binary file not shown.
297
Lab/Lab3/source/21281280-柯劲帆-第3次实验.md
Normal file
297
Lab/Lab3/source/21281280-柯劲帆-第3次实验.md
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
<h1><center>北京交通大学实验报告</center></h1>
|
||||||
|
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">课程名称</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">操作系统</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">实验题目</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">Linux进程控制的实现机制</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">学号</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">21281280</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">姓名</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">柯劲帆</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">班级</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">物联网2101班</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">指导老师</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">何永忠</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">报告日期</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 210px; font-weight: bold; text-align: left;">2023年11月6日</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 1. 开发运行环境和工具
|
||||||
|
|
||||||
|
- **代码阅读环境**:Windows11 + VS Code
|
||||||
|
- **开发测试环境**:Bochs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 2. 实验过程、分析和结论
|
||||||
|
|
||||||
|
## 2.1. fork系统调用和内核函数
|
||||||
|
|
||||||
|
首先在`init/main.c`-->`main()`中看到了`fork()`函数
|
||||||
|
|
||||||
|
```c
|
||||||
|
if (!fork()) { /* we count on this going ok */
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
即为如果`fork()`没有发现父进程(后面会讲到),则初始化系统,创建系统初始进程。
|
||||||
|
|
||||||
|
追踪`fork()`,发现在`main.c`开头有一行:
|
||||||
|
|
||||||
|
```c
|
||||||
|
static inline _syscall0(int,fork)
|
||||||
|
```
|
||||||
|
|
||||||
|
即调用`fork()`时,编译器会将`fork()`内嵌为`_syscall0(int,fork)`,即在编译时直接替换为`_syscall0(int,fork)`的函数代码,以免调用堆栈。
|
||||||
|
|
||||||
|
追踪`_syscall0()`,在`include/unistd.h`中:
|
||||||
|
|
||||||
|
```asm
|
||||||
|
#define _syscall0(type,name) \
|
||||||
|
type name(void) \
|
||||||
|
{ \
|
||||||
|
long __res; \
|
||||||
|
__asm__ volatile ("int $0x80" \
|
||||||
|
: "=a" (__res) \
|
||||||
|
: "0" (__NR_##name)); \
|
||||||
|
if (__res >= 0) \
|
||||||
|
return (type) __res; \
|
||||||
|
errno = -__res; \
|
||||||
|
return -1; \
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
即,调用`fork()`就是在调用
|
||||||
|
|
||||||
|
```asm
|
||||||
|
"int $0x80" : "=a" (__res) : "0" (__NR_fork)
|
||||||
|
```
|
||||||
|
|
||||||
|
- `"int $0x80"`:表示触发软中断。在x86体系结构中,软中断0x80用于进入内核态进行系统调用。
|
||||||
|
- `: "=a" (__res)`:对输出操作数的约束。`=a` 表示将寄存器 `eax` 的值分配给 `__res`,并且这个值会在系统调用结束后存储系统调用的返回值。
|
||||||
|
- `: "0" (__NR_fork)`:对输入操作数的约束。`0` 表示使用与前面输出操作数相同的寄存器,这里是 `eax`。`__NR_fork` 是系统调用号的宏,被定义为`2`,用于标识调用的具体系统调用。
|
||||||
|
|
||||||
|
那么调用`fork()`时,就是调用了2号系统软中断。
|
||||||
|
|
||||||
|
接下来到`kernel/system_call.s`中查看软中断函数`_system_call`代码是如何执行的:首先进行了一系列参数的检查和原寄存器入栈保存操作,这里不予赘述。然后执行了
|
||||||
|
|
||||||
|
```asm
|
||||||
|
call _sys_call_table(,%eax,4)
|
||||||
|
```
|
||||||
|
|
||||||
|
按照传进来的参数,实际上调用了`_sys_call_table(,2,4)`
|
||||||
|
|
||||||
|
由于这是汇编文件,调用`_sys_call_table()`实际上就是在调用C语言代码中的`sys_call_table()`函数,因为在编译时,编译器会在C代码函数前加上`_`作为其在汇编代码中的命名(实验证明见附录)。
|
||||||
|
|
||||||
|
那么追踪`sys_call_table()`,在`include/linux/sys.h`中发现了系统调用表:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
|
||||||
|
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
|
||||||
|
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
|
||||||
|
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
|
||||||
|
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
|
||||||
|
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
|
||||||
|
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
|
||||||
|
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
|
||||||
|
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
|
||||||
|
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
|
||||||
|
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
|
||||||
|
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
|
||||||
|
sys_setreuid,sys_setregid };
|
||||||
|
```
|
||||||
|
|
||||||
|
其中变量类型`fn_ptr`是函数指针。所以实际上`_sys_call_table(,2,4)`调用了第3个`sys_fork`函数。`sys_fork`函数在汇编后会被命名成`_sys_fork`。
|
||||||
|
|
||||||
|
我在`kernel/system_call.s`中找到了对其汇编后的调用`_sys_fork`,即系统调用`fork`的函数原型就是:
|
||||||
|
|
||||||
|
```asm
|
||||||
|
_sys_fork:
|
||||||
|
call _find_empty_process
|
||||||
|
testl %eax,%eax
|
||||||
|
js 1f
|
||||||
|
push %gs
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
|
pushl %ebp
|
||||||
|
pushl %eax
|
||||||
|
call _copy_process
|
||||||
|
addl $20,%esp
|
||||||
|
1: ret
|
||||||
|
```
|
||||||
|
|
||||||
|
其中依次调用了`_find_empty_process`和`_copy_process`函数。这两个函数的C代码`find_empty_process()`和`copy_process()`在`kernel/fork.c`中:
|
||||||
|
|
||||||
|
- `find_empty_process()`:寻找一个空闲的pid,并为其在任务数组中为新任务寻找一个空闲项,并返回项号。
|
||||||
|
- `copy_process()`:复制父进程的各项值并初始化(这么做是因为复制比新建快)。
|
||||||
|
|
||||||
|
在这之中,代码为新进程创建了进程控制块`struct task_struct *p`,到`include/linux/sched.h`中跟踪其定义:
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct task_struct {
|
||||||
|
/* these are hardcoded - don't touch */
|
||||||
|
long state; /* -1 unrunnable, 0 runnable, >0 stopped */
|
||||||
|
// 表示进程的状态,-1 表示不可运行,0 表示可运行,大于0 表示已停止。
|
||||||
|
long counter; // 计时器,用于调度,当计时器减至0时,进程可能被调度出去。
|
||||||
|
long priority; // 进程的优先级。
|
||||||
|
long signal; // 当前进程正在处理的信号。
|
||||||
|
struct sigaction sigaction[32]; // 存储信号处理程序的数组。
|
||||||
|
long blocked; /* bitmap of masked signals */
|
||||||
|
// 用于表示被阻塞的信号的位图。
|
||||||
|
/* various fields */
|
||||||
|
int exit_code;
|
||||||
|
unsigned long start_code,end_code,end_data,brk,start_stack;
|
||||||
|
long pid,father,pgrp,session,leader;
|
||||||
|
// pid 进程ID
|
||||||
|
// father 父进程ID
|
||||||
|
// pgrp 进程组ID
|
||||||
|
// session 会话ID
|
||||||
|
// leader 会话的领导者ID
|
||||||
|
unsigned short uid,euid,suid; // 用户ID、有效用户ID、保存的用户ID
|
||||||
|
unsigned short gid,egid,sgid; // 组ID、有效组ID、保存的组ID
|
||||||
|
long alarm; // 进程的闹钟定时器
|
||||||
|
long utime,stime,cutime,cstime,start_time;
|
||||||
|
// utime 用户态运行时间
|
||||||
|
// stime 系统态运行时间
|
||||||
|
// cutime 子进程的用户态运行时间
|
||||||
|
// cstime 子进程的系统态运行时间
|
||||||
|
// start_time 进程开始运行的时间
|
||||||
|
unsigned short used_math; // 表示是否使用了数学协处理器
|
||||||
|
/* file system info */
|
||||||
|
int tty; // 表示进程是否有终端
|
||||||
|
/* -1 if no tty, so it must be signed */
|
||||||
|
unsigned short umask; // 文件创建的权限屏蔽掩码
|
||||||
|
struct m_inode * pwd; // 当前工作目录
|
||||||
|
struct m_inode * root; // 当前根目录
|
||||||
|
struct m_inode * executable; // 执行文件的指针
|
||||||
|
unsigned long close_on_exec; // 用于在执行新程序时关闭文件的标志位
|
||||||
|
struct file * filp[NR_OPEN]; // 文件指针数组,用于表示打开的文件
|
||||||
|
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
|
||||||
|
struct desc_struct ldt[3]; // 进程的局部描述符表,包含代码段、数据段、堆栈段的描述符
|
||||||
|
/* tss for this task */
|
||||||
|
struct tss_struct tss; // 任务状态段,包含了一些处理器的状态信息
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
最后,返回新建进程的pid。
|
||||||
|
|
||||||
|
于是,`fork`调用就成功创建了新的进程和pid,并把pid返回给了调用`fork`的进程。
|
||||||
|
|
||||||
|
## 2.2. exit系统调用和内核函数
|
||||||
|
|
||||||
|
首先在`init/main.c`-->`main()`中看到了`_exit()`函数:
|
||||||
|
|
||||||
|
```c
|
||||||
|
if (!(pid=fork())) {
|
||||||
|
close(0);
|
||||||
|
if (open("/etc/rc",O_RDONLY,0))
|
||||||
|
_exit(1);
|
||||||
|
execve("/bin/sh",argv_rc,envp_rc);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
追踪`_exit()`,到`lib/_exit.c`中看到定义:
|
||||||
|
|
||||||
|
```c
|
||||||
|
volatile void _exit(int exit_code)
|
||||||
|
{
|
||||||
|
__asm__("int $0x80"::"a" (__NR_exit),"b" (exit_code));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
和`fork()`一样,`_exit()`也是使用了系统中断来执行。
|
||||||
|
|
||||||
|
`__NR_exit`的宏定义为系统调用号1,所以实际上:`__NR_exit` 的值被加载到 `%eax` 寄存器;`exit_code` 的值被加载到 `%ebx` 寄存器,作为 `exit` 系统调用的参数,即退出码。
|
||||||
|
|
||||||
|
于是在`kernel/system_call.s`中,软中断函数`_system_call`代码执行了`call _sys_call_table(,1,4)`,即调用了系统调用表中的`sys_exit`。
|
||||||
|
|
||||||
|
`sys_exit`的定义在`kernel/exit.c`中:
|
||||||
|
|
||||||
|
```c
|
||||||
|
int sys_exit(int error_code)
|
||||||
|
{
|
||||||
|
return do_exit((error_code&0xff)<<8);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
再追踪`do_exit()`的代码,主要执行以下任务:
|
||||||
|
|
||||||
|
- 释放当前进程的页表
|
||||||
|
- 处理与当前进程相关的其他进程
|
||||||
|
- 关闭当前进程打开的文件
|
||||||
|
- 释放当前进程的pwd、root和executable相关资源
|
||||||
|
- 处理当前进程是会话领导者等情况
|
||||||
|
- 通知父进程
|
||||||
|
- 调度下一个进程
|
||||||
|
|
||||||
|
至此,本进程结束退出,exit系统调用完毕。
|
||||||
|
|
||||||
|
## 2.3. 原子性实现
|
||||||
|
|
||||||
|
纵观代码,进程间的切换主要有两种方式,一种是主动切换,如`pause()`,其作用就是主动将当前进程挂起,切换到下一个进程任务执行,需要调用`schedule()`。在`schedule()`中会判断要操作的进程的状态是否是可中断的。
|
||||||
|
|
||||||
|
另一种是通过开关中断,主动允许/不允许中断打断当前进程。在`include/asm/system.h`中:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define sti() __asm__ ("sti"::)
|
||||||
|
#define cli() __asm__ ("cli"::)
|
||||||
|
```
|
||||||
|
|
||||||
|
因此,在代码中使用`sti()`和`cli()`就能实现开/关中断。
|
||||||
|
|
||||||
|
在`fork`和`exit`系统调用代码中,并没有调用`pause()`主动切换,也不会因为硬件中断而导致共享资源出错(对栈的使用得当),因此实现了原子性。
|
||||||
|
|
||||||
|
## 2.4. 修改fork系统调用
|
||||||
|
|
||||||
|
修改`kernel/fork.c`文件中`copy_process()`函数定义,在`return`前打印出新进程的pid和状态:
|
||||||
|
|
||||||
|
```c
|
||||||
|
p->state = TASK_RUNNING; /* do this last, just in case */
|
||||||
|
printk("pid=%d, state=%d", last_pid, p->state);
|
||||||
|
return last_pid;
|
||||||
|
```
|
||||||
|
|
||||||
|
运行结果如下:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
`state`为0表示当前进程(在刚刚创建时)是就绪态和运行态。
|
||||||
|
|
||||||
|
## 2.5. Makefile文件
|
||||||
|
|
||||||
|
首先,文件定义了编译必要的工具和选项,以及根设备、目标文件等;
|
||||||
|
|
||||||
|
接下来定义了编译规则,如从`.c`文件编译出`.s`文件等;
|
||||||
|
|
||||||
|
然后定义最后生成`Image`镜像文件;
|
||||||
|
|
||||||
|
规定`Image`文件的构建规则、写入磁盘规则;
|
||||||
|
|
||||||
|
定义构建工具的规则;
|
||||||
|
|
||||||
|
定义编译完后要清理的文件;
|
||||||
|
|
||||||
|
创建备份;
|
||||||
|
|
||||||
|
规定项目源码文件之间构建的依赖关系。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 附录
|
||||||
|
|
||||||
|
编译`kernel/fork.c`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
[usr/src/linux/kernel]# gcc -E fork.c -fork.i
|
||||||
|
[usr/src/linux/kernel]# gcc -S fork.i -fork.s
|
||||||
|
[usr/src/linux/kernel]# vi fork.s
|
||||||
|
```
|
||||||
|
|
||||||
|
则可以看到,函数`verify_area()`变成了`_verify_area`,函数`copy_mem()`变成了`_copy_mem`。
|
BIN
Lab/Lab3/source/p1.png
Normal file
BIN
Lab/Lab3/source/p1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
BIN
Lab/Lab4/21281280-柯劲帆-第4次实验.pdf
Normal file
BIN
Lab/Lab4/21281280-柯劲帆-第4次实验.pdf
Normal file
Binary file not shown.
265
Lab/Lab4/code/main.cpp
Normal file
265
Lab/Lab4/code/main.cpp
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int preprocess_task_size(int);
|
||||||
|
int find_free_block_ff(int, struct Block**);
|
||||||
|
int find_free_block_bf(int, struct Block**);
|
||||||
|
int queue_push(int);
|
||||||
|
int queue_pop();
|
||||||
|
int get_command(FILE*);
|
||||||
|
int fork(int);
|
||||||
|
void kill(int);
|
||||||
|
int run(char*);
|
||||||
|
void init();
|
||||||
|
void clean_stdin();
|
||||||
|
|
||||||
|
#define MAX_NUM_TASKS 128
|
||||||
|
#define MAX_NUM_WAIT 512
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
int free;
|
||||||
|
int start;
|
||||||
|
int size;
|
||||||
|
struct Block* next, *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Task {
|
||||||
|
int start;
|
||||||
|
int size;
|
||||||
|
int pid;
|
||||||
|
struct Block* block;
|
||||||
|
};
|
||||||
|
|
||||||
|
int sys_size = 384 << 10, usr_size = 128 << 10;
|
||||||
|
struct Block* sys_space, *usr_space;
|
||||||
|
struct Task* tasks;
|
||||||
|
int last_pid = -1;
|
||||||
|
int match_method = -1;
|
||||||
|
int wait_queue[MAX_NUM_WAIT];
|
||||||
|
int wait_q_begin = 0, wait_q_end = 0;
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
init();
|
||||||
|
while (get_command(stdin) >= 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_command(FILE* stream) {
|
||||||
|
printf("user> ");
|
||||||
|
char input_str[128] = {0};
|
||||||
|
fgets(input_str, 127, stream);
|
||||||
|
if (stream != stdin) printf("%s", input_str);
|
||||||
|
|
||||||
|
int split_index = 0;
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
if (input_str[i] == '\0') break;
|
||||||
|
if (input_str[i] == ' ') {
|
||||||
|
input_str[i] = '\0';
|
||||||
|
split_index = i;
|
||||||
|
}
|
||||||
|
if (input_str[i] == '\n') {
|
||||||
|
input_str[i] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* command = input_str, * arguments = input_str + split_index + 1;
|
||||||
|
|
||||||
|
if (!strcmp(command, "exit")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "fork") == 0) {
|
||||||
|
int input_size = atoi(arguments);
|
||||||
|
if (input_size <= 0) {
|
||||||
|
printf("Bad input size. Input number must larger than ZERO.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int pid = fork(input_size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(command, "kill")) {
|
||||||
|
int input_pid = atoi(arguments);
|
||||||
|
if (input_pid < 0) {
|
||||||
|
printf("Bad input PID. Input number must not smaller than ZERO.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
kill(input_pid);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(input_str, "print")) {
|
||||||
|
printf("print.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(input_str, "run")) {
|
||||||
|
int result = run(arguments);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if (!strcmp(input_str, ""));
|
||||||
|
else {
|
||||||
|
printf("Command not found.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kill(int pid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
sys_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
sys_space->free = 1;
|
||||||
|
sys_space->start = 0;
|
||||||
|
sys_space->size = sys_size;
|
||||||
|
sys_space->next = NULL;
|
||||||
|
sys_space->last = NULL;
|
||||||
|
|
||||||
|
usr_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
usr_space->free = 1;
|
||||||
|
usr_space->start = sys_size;
|
||||||
|
usr_space->size = usr_size;
|
||||||
|
usr_space->next = NULL;
|
||||||
|
usr_space->last = NULL;
|
||||||
|
|
||||||
|
tasks = (struct Task*)malloc(MAX_NUM_TASKS * sizeof(struct Task));
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) tasks[i].pid = -1;
|
||||||
|
|
||||||
|
ask_match_method:
|
||||||
|
printf("Choose a matching method:\n 1. First Fit\n 2. Best Fit\n");
|
||||||
|
scanf("%d", &match_method);
|
||||||
|
clean_stdin();
|
||||||
|
if (match_method != 1 && match_method != 2) {
|
||||||
|
printf("Bad input. Choose again.\n");
|
||||||
|
goto ask_match_method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fork(int size) {
|
||||||
|
int pid;
|
||||||
|
int task_index = -1;
|
||||||
|
repeat:
|
||||||
|
last_pid++;
|
||||||
|
if (last_pid < 0) last_pid = 0;
|
||||||
|
pid = last_pid;
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) {
|
||||||
|
if (tasks[i].pid >= 0) continue;
|
||||||
|
if (tasks[i].pid == pid) goto repeat;
|
||||||
|
task_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (task_index == -1) return -1;
|
||||||
|
|
||||||
|
size = preprocess_task_size(size);
|
||||||
|
tasks[task_index].size = size;
|
||||||
|
int start_loc = -1;
|
||||||
|
if (match_method == 1) start_loc = find_free_block_ff(size, &tasks[task_index].block);
|
||||||
|
else start_loc = find_free_block_bf(size, &tasks[task_index].block);
|
||||||
|
if (start_loc >= 0) {
|
||||||
|
tasks[task_index].start = start_loc;
|
||||||
|
tasks[task_index].pid = pid;
|
||||||
|
tasks[task_index].size = size;
|
||||||
|
printf("Fork succeed. PID is %d . Block size is %d bit.\n", pid, size);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
printf("Fork failed. Out of Memory. Trying to push into wait list.\n");
|
||||||
|
int tmp = queue_push(size);
|
||||||
|
if (tmp < 0) printf("Error: Push into wait list failed.\n");
|
||||||
|
else printf("Push into wait list succeed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_free_block_ff(int size, struct Block** block_p) {
|
||||||
|
struct Block* now = usr_space;
|
||||||
|
while (1) {
|
||||||
|
if (now == NULL) return -1;
|
||||||
|
if (now->free != 0 && now->size >= size) break;
|
||||||
|
now = now->next;
|
||||||
|
}
|
||||||
|
*block_p = now;
|
||||||
|
if (now->size == size) return now->start;
|
||||||
|
struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
free_space->free = 1;
|
||||||
|
free_space->last = now;
|
||||||
|
free_space->next = now->next;
|
||||||
|
free_space->size = now->size - size;
|
||||||
|
free_space->start = now->start + size;
|
||||||
|
|
||||||
|
now->free = 0;
|
||||||
|
now->next = free_space;
|
||||||
|
now->size = size;
|
||||||
|
return now->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_free_block_bf(int size, struct Block** block_p) {
|
||||||
|
struct Block* now = usr_space, *best_block;
|
||||||
|
int best_size = 0xffffff;
|
||||||
|
while (1) {
|
||||||
|
if (now == NULL) break;
|
||||||
|
if (now->free != 0 && now->size >= size && best_size >= now->size) {
|
||||||
|
best_block = now;
|
||||||
|
best_size = now->size;
|
||||||
|
}
|
||||||
|
now = now->next;
|
||||||
|
}
|
||||||
|
if (best_size == 0xffffff) return -1;
|
||||||
|
*block_p = best_block;
|
||||||
|
if (best_block->size == size) return best_block->start;
|
||||||
|
struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
free_space->free = 1;
|
||||||
|
free_space->last = best_block;
|
||||||
|
free_space->next = best_block->next;
|
||||||
|
free_space->size = best_block->size - size;
|
||||||
|
free_space->start = best_block->start + size;
|
||||||
|
|
||||||
|
best_block->free = 0;
|
||||||
|
best_block->next = free_space;
|
||||||
|
best_block->size = size;
|
||||||
|
return best_block->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run(char* path) {
|
||||||
|
FILE* f = NULL;
|
||||||
|
f = fopen(path, "r+");
|
||||||
|
if (f == NULL) {
|
||||||
|
printf("Error: Invalid file path.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 0;
|
||||||
|
while(!feof(f) && result != -1) result = get_command(f);
|
||||||
|
fclose(f);
|
||||||
|
printf("%d\n", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int preprocess_task_size(int size) {
|
||||||
|
size = size & 0x400;
|
||||||
|
size = size + 0x400;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int queue_push(int size) {
|
||||||
|
if ((wait_q_end + 1) % MAX_NUM_WAIT == wait_q_begin) {
|
||||||
|
printf("Wait list full.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wait_queue[wait_q_end++] = size;
|
||||||
|
wait_q_end %= MAX_NUM_WAIT;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int queue_pop() {
|
||||||
|
if (wait_q_begin == wait_q_end) {
|
||||||
|
printf("Wait list empty.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return wait_queue[wait_q_begin++];
|
||||||
|
}
|
||||||
|
|
||||||
|
void clean_stdin() {
|
||||||
|
int c;
|
||||||
|
do {
|
||||||
|
c = getchar();
|
||||||
|
} while (c != '\n' && c != EOF);
|
||||||
|
}
|
BIN
Lab/Lab4/code/main.exe
Normal file
BIN
Lab/Lab4/code/main.exe
Normal file
Binary file not shown.
4
Lab/Lab4/code/test.txt
Normal file
4
Lab/Lab4/code/test.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
fork 1023
|
||||||
|
fork -1
|
||||||
|
exit
|
||||||
|
111
|
Binary file not shown.
824
Lab/Lab4/source/21281280-柯劲帆-第4次实验.md
Normal file
824
Lab/Lab4/source/21281280-柯劲帆-第4次实验.md
Normal file
@ -0,0 +1,824 @@
|
|||||||
|
<h1><center>北京交通大学实验报告</center></h1>
|
||||||
|
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">课程名称</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">操作系统</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">实验题目</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">动态可重定位分区内存管理模拟设计与实现</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">学号</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">21281280</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">姓名</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">柯劲帆</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">班级</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">物联网2101班</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">指导老师</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">何永忠</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">报告日期</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">2023年11月26日</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 1. 开发运行环境和工具
|
||||||
|
|
||||||
|
| 操作系统 | Linux内核版本 | 处理器 | GCC版本 |
|
||||||
|
| :---------: | :-----------------------: | :--------------------------------------: | :-------------------------------: |
|
||||||
|
| Deepin 20.9 | 5.18.17-amd64-desktop-hwe | Intel(R) Core(TM) i3-2330M CPU @ 2.20GHz | gcc (Uos 8.3.0.3-3+rebuild) 8.3.0 |
|
||||||
|
|
||||||
|
- **其他工具**:
|
||||||
|
- **编辑**:VSCode
|
||||||
|
- **编译和运行**:Terminal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 2. 实验过程、分析和结论
|
||||||
|
|
||||||
|
## 2.1. 初始化
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MAX_NUM_TASKS 128
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
int start;
|
||||||
|
int size;
|
||||||
|
int pid;
|
||||||
|
struct Block* next, * last;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Task {
|
||||||
|
int start;
|
||||||
|
int size;
|
||||||
|
int pid;
|
||||||
|
struct Block* block;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Request {
|
||||||
|
int size;
|
||||||
|
struct Request* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int preprocess_task_size(int);
|
||||||
|
int find_free_block_ff(int, struct Block**);
|
||||||
|
int find_free_block_bf(int, struct Block**);
|
||||||
|
void queue_push(int);
|
||||||
|
int queue_pop();
|
||||||
|
int get_command(FILE*);
|
||||||
|
int fork_process(int);
|
||||||
|
void kill_process(int);
|
||||||
|
int run(char*);
|
||||||
|
void init();
|
||||||
|
void clean_stdin();
|
||||||
|
void execute_wait_list();
|
||||||
|
void print();
|
||||||
|
|
||||||
|
int sys_size = 128 << 20, usr_size = 384 << 20;
|
||||||
|
struct Block* sys_space = NULL, * usr_space = NULL;
|
||||||
|
struct Task* tasks = NULL;
|
||||||
|
struct Request* waitlist_begin = NULL, * waitlist_end = NULL;
|
||||||
|
int waitlist_size = 0;
|
||||||
|
int last_pid = -1;
|
||||||
|
int match_method = -1;
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
init();
|
||||||
|
while (get_command(stdin) >= 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
sys_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
sys_space->pid = -1;
|
||||||
|
sys_space->start = 0;
|
||||||
|
sys_space->size = sys_size;
|
||||||
|
sys_space->next = NULL;
|
||||||
|
sys_space->last = NULL;
|
||||||
|
|
||||||
|
usr_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
usr_space->pid = -1;
|
||||||
|
usr_space->start = sys_size;
|
||||||
|
usr_space->size = usr_size;
|
||||||
|
usr_space->next = NULL;
|
||||||
|
usr_space->last = NULL;
|
||||||
|
|
||||||
|
tasks = (struct Task*)malloc(MAX_NUM_TASKS * sizeof(struct Task));
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) tasks[i].pid = -1;
|
||||||
|
|
||||||
|
ask_match_method:
|
||||||
|
printf("Choose a matching method:\n 1. First Fit\n 2. Best Fit\n");
|
||||||
|
printf("choose> ");
|
||||||
|
scanf("%d", &match_method);
|
||||||
|
clean_stdin();
|
||||||
|
if (match_method != 1 && match_method != 2) {
|
||||||
|
printf("Bad input. Choose again.\n");
|
||||||
|
goto ask_match_method;
|
||||||
|
}
|
||||||
|
|
||||||
|
waitlist_begin = (struct Request*)malloc(sizeof(struct Request));
|
||||||
|
waitlist_end = waitlist_begin;
|
||||||
|
waitlist_begin->next = NULL;
|
||||||
|
waitlist_begin->size = -1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.2. 申请内存分配操作
|
||||||
|
|
||||||
|
```c
|
||||||
|
int fork_process(int size) {
|
||||||
|
int pid;
|
||||||
|
int task_index = -1;
|
||||||
|
repeat:
|
||||||
|
last_pid++;
|
||||||
|
if (last_pid < 0) last_pid = 0;
|
||||||
|
pid = last_pid;
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) {
|
||||||
|
if (tasks[i].pid >= 0 && tasks[i].pid == pid) goto repeat;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) {
|
||||||
|
if (tasks[i].pid >= 0) continue;
|
||||||
|
task_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (task_index == -1) return -1;
|
||||||
|
|
||||||
|
size = preprocess_task_size(size);
|
||||||
|
tasks[task_index].size = size;
|
||||||
|
int start_loc = -1;
|
||||||
|
if (match_method == 1) start_loc = find_free_block_ff(size, &tasks[task_index].block);
|
||||||
|
else start_loc = find_free_block_bf(size, &tasks[task_index].block);
|
||||||
|
if (start_loc >= 0) {
|
||||||
|
tasks[task_index].start = start_loc;
|
||||||
|
tasks[task_index].pid = pid;
|
||||||
|
tasks[task_index].size = size;
|
||||||
|
tasks[task_index].block->pid = pid;
|
||||||
|
printf("Fork succeed. PID is %d . Block size is %d bits.\n", pid, size);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
printf("Fork failed. Out of Memory. Trying to push into wait list.\n");
|
||||||
|
queue_push(size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_free_block_ff(int size, struct Block** block_p) {
|
||||||
|
struct Block* now = usr_space;
|
||||||
|
int cnt = 1;
|
||||||
|
while (1) {
|
||||||
|
if (now == NULL) return -1;
|
||||||
|
if (now->pid < 0 && now->size >= size) break;
|
||||||
|
now = now->next;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
printf("Use %d times to find free block.\n", cnt);
|
||||||
|
*block_p = now;
|
||||||
|
if (now->size == size) return now->start;
|
||||||
|
struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
free_space->pid = -1;
|
||||||
|
free_space->last = now;
|
||||||
|
free_space->next = now->next;
|
||||||
|
free_space->size = now->size - size;
|
||||||
|
free_space->start = now->start + size;
|
||||||
|
|
||||||
|
now->pid = -2;
|
||||||
|
now->next = free_space;
|
||||||
|
now->size = size;
|
||||||
|
return now->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_free_block_bf(int size, struct Block** block_p) {
|
||||||
|
struct Block* now = usr_space, * best_block;
|
||||||
|
int best_size = 0x7fffffff;
|
||||||
|
int cnt = 1;
|
||||||
|
while (1) {
|
||||||
|
if (now == NULL) break;
|
||||||
|
if (now->pid < 0 && now->size >= size && best_size >= now->size) {
|
||||||
|
best_block = now;
|
||||||
|
best_size = now->size;
|
||||||
|
}
|
||||||
|
now = now->next;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
if (best_size == 0x7fffffff) return -1;
|
||||||
|
printf("Use %d times to find free block.\n", cnt);
|
||||||
|
*block_p = best_block;
|
||||||
|
if (best_block->size == size) return best_block->start;
|
||||||
|
struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
free_space->pid = -1;
|
||||||
|
free_space->last = best_block;
|
||||||
|
free_space->next = best_block->next;
|
||||||
|
free_space->size = best_block->size - size;
|
||||||
|
free_space->start = best_block->start + size;
|
||||||
|
|
||||||
|
best_block->pid = -2;
|
||||||
|
best_block->next = free_space;
|
||||||
|
best_block->size = size;
|
||||||
|
return best_block->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run(char* path) {
|
||||||
|
FILE* f = NULL;
|
||||||
|
f = fopen(path, "r+");
|
||||||
|
if (f == NULL) {
|
||||||
|
printf("Error: Invalid file path.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 0;
|
||||||
|
while (!feof(f) && result != -1) result = get_command(f);
|
||||||
|
fclose(f);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int preprocess_task_size(int size) {
|
||||||
|
int lower = size & 0x3ff;
|
||||||
|
if (lower == 0) return size;
|
||||||
|
int upper = size - lower;
|
||||||
|
size = upper + 0x400;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_push(int size) {
|
||||||
|
waitlist_begin->next = (struct Request*)malloc(sizeof(struct Request));
|
||||||
|
waitlist_begin = waitlist_begin->next;
|
||||||
|
waitlist_begin->next = NULL;
|
||||||
|
waitlist_begin->size = size;
|
||||||
|
waitlist_size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int queue_pop() {
|
||||||
|
if (!waitlist_size) {
|
||||||
|
printf("Wait list empty.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
struct Request* tmp = waitlist_end;
|
||||||
|
waitlist_end = waitlist_end->next;
|
||||||
|
free(tmp);
|
||||||
|
waitlist_size--;
|
||||||
|
return waitlist_end->size;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.3. 回收
|
||||||
|
|
||||||
|
```c
|
||||||
|
void kill_process(int pid) {
|
||||||
|
struct Block* block = NULL;
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) {
|
||||||
|
if (tasks[i].pid != pid) continue;
|
||||||
|
|
||||||
|
block = tasks[i].block;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (block == NULL) {
|
||||||
|
printf("Error: PID dosen't exist.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (block->last && block->last->pid < 0 && block->next && block->next->pid < 0) {
|
||||||
|
struct Block* free_block = block->last;
|
||||||
|
free_block->next = block->next->next;
|
||||||
|
free_block->size += block->size + block->next->size;
|
||||||
|
if (free_block->next) free_block->next->last = free_block;
|
||||||
|
free(block->next);
|
||||||
|
free(block);
|
||||||
|
}
|
||||||
|
else if (block->last && block->last->pid < 0) {
|
||||||
|
struct Block* free_block = block->last;
|
||||||
|
free_block->next = block->next;
|
||||||
|
free_block->size += block->size;
|
||||||
|
if (free_block->next) free_block->next->last = free_block;
|
||||||
|
free(block);
|
||||||
|
}
|
||||||
|
else if (block->next && block->next->pid < 0) {
|
||||||
|
struct Block* free_block = block;
|
||||||
|
free_block->size += block->next->size;
|
||||||
|
free_block->next = block->next->next;
|
||||||
|
free_block->pid = -1;
|
||||||
|
if (free_block->next) free_block->next->last = free_block;
|
||||||
|
free(block->next);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
block->pid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_wait_list();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute_wait_list() {
|
||||||
|
int size = -1, loop_num = waitlist_size;
|
||||||
|
for (int i = 0; i < loop_num; i++) {
|
||||||
|
size = queue_pop();
|
||||||
|
fork_process(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.4. 其他代码
|
||||||
|
|
||||||
|
```c
|
||||||
|
int get_command(FILE* stream) {
|
||||||
|
printf("user> ");
|
||||||
|
char input_str[128] = { 0 };
|
||||||
|
fgets(input_str, 127, stream);
|
||||||
|
if (stream != stdin) printf("%s", input_str);
|
||||||
|
|
||||||
|
int split_index = 0;
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
if (input_str[i] == '\0') break;
|
||||||
|
if (input_str[i] == ' ') {
|
||||||
|
input_str[i] = '\0';
|
||||||
|
split_index = i;
|
||||||
|
}
|
||||||
|
if (input_str[i] == '\n') {
|
||||||
|
input_str[i] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* command = input_str, * arguments = input_str + split_index + 1;
|
||||||
|
|
||||||
|
if (!strcmp(command, "exit")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "fork") == 0) {
|
||||||
|
int input_size = atoi(arguments);
|
||||||
|
if (input_size <= 0) {
|
||||||
|
printf("Bad input size. Input number must larger than ZERO.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (input_size > usr_size) {
|
||||||
|
printf("Bad input size. Input number must smaller than %d bits.\n", usr_size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int pid = fork_process(input_size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(command, "kill")) {
|
||||||
|
int input_pid = atoi(arguments);
|
||||||
|
if (input_pid < 0) {
|
||||||
|
printf("Bad input PID. Input number must not smaller than ZERO.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
kill_process(input_pid);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(input_str, "print")) {
|
||||||
|
print();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(input_str, "run")) {
|
||||||
|
int result = run(arguments);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if (input_str[0] == '\0');
|
||||||
|
else {
|
||||||
|
printf("Command not found.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
char str[2][13] = { {" True"}, {" False"} };
|
||||||
|
char* s;
|
||||||
|
struct Block* p = sys_space;
|
||||||
|
printf("+----------------------------------------------------------------+\n");
|
||||||
|
printf("| System Space |\n");
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
printf("| Free | Begin | Size | End | PID |\n");
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
while (p != NULL) {
|
||||||
|
s = p->pid < 0 ? str[0] : str[1];
|
||||||
|
printf("|%s|%12d|%12d|%12d|%12d|\n", s, p->start, p->size, p->start + p->size - 1, p->pid);
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
printf("+----------------------------------------------------------------+\n\n");
|
||||||
|
|
||||||
|
p = usr_space;
|
||||||
|
printf("+----------------------------------------------------------------+\n");
|
||||||
|
printf("| User Space |\n");
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
printf("| Free | Begin | Size | End | PID |\n");
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
while (p != NULL) {
|
||||||
|
s = p->pid < 0 ? str[0] : str[1];
|
||||||
|
printf("|%s|%12d|%12d|%12d|%12d|\n", s, p->start, p->size, p->start + p->size - 1, p->pid);
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
printf("+----------------------------------------------------------------+\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void clean_stdin() {
|
||||||
|
int c;
|
||||||
|
do {
|
||||||
|
c = getchar();
|
||||||
|
} while (c != '\n' && c != EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int run(char* path) {
|
||||||
|
FILE* f = NULL;
|
||||||
|
f = fopen(path, "r+");
|
||||||
|
if (f == NULL) {
|
||||||
|
printf("Error: Invalid file path.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 0;
|
||||||
|
while (!feof(f) && result != -1) result = get_command(f);
|
||||||
|
fclose(f);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 附录
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MAX_NUM_TASKS 128
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
int start;
|
||||||
|
int size;
|
||||||
|
int pid;
|
||||||
|
struct Block* next, * last;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Task {
|
||||||
|
int start;
|
||||||
|
int size;
|
||||||
|
int pid;
|
||||||
|
struct Block* block;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Request {
|
||||||
|
int size;
|
||||||
|
struct Request* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int preprocess_task_size(int);
|
||||||
|
int find_free_block_ff(int, struct Block**);
|
||||||
|
int find_free_block_bf(int, struct Block**);
|
||||||
|
void queue_push(int);
|
||||||
|
int queue_pop();
|
||||||
|
int get_command(FILE*);
|
||||||
|
int fork_process(int);
|
||||||
|
void kill_process(int);
|
||||||
|
int run(char*);
|
||||||
|
void init();
|
||||||
|
void clean_stdin();
|
||||||
|
void execute_wait_list();
|
||||||
|
void print();
|
||||||
|
|
||||||
|
int sys_size = 128 << 20, usr_size = 384 << 20;
|
||||||
|
struct Block* sys_space = NULL, * usr_space = NULL;
|
||||||
|
struct Task* tasks = NULL;
|
||||||
|
struct Request* waitlist_begin = NULL, * waitlist_end = NULL;
|
||||||
|
int waitlist_size = 0;
|
||||||
|
int last_pid = -1;
|
||||||
|
int match_method = -1;
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
init();
|
||||||
|
while (get_command(stdin) >= 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_command(FILE* stream) {
|
||||||
|
printf("user> ");
|
||||||
|
char input_str[128] = { 0 };
|
||||||
|
fgets(input_str, 127, stream);
|
||||||
|
if (stream != stdin) printf("%s", input_str);
|
||||||
|
|
||||||
|
int split_index = 0;
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
if (input_str[i] == '\0') break;
|
||||||
|
if (input_str[i] == ' ') {
|
||||||
|
input_str[i] = '\0';
|
||||||
|
split_index = i;
|
||||||
|
}
|
||||||
|
if (input_str[i] == '\n') {
|
||||||
|
input_str[i] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* command = input_str, * arguments = input_str + split_index + 1;
|
||||||
|
|
||||||
|
if (!strcmp(command, "exit")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "fork") == 0) {
|
||||||
|
int input_size = atoi(arguments);
|
||||||
|
if (input_size <= 0) {
|
||||||
|
printf("Bad input size. Input number must larger than ZERO.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (input_size > usr_size) {
|
||||||
|
printf("Bad input size. Input number must smaller than %d bits.\n", usr_size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int pid = fork_process(input_size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(command, "kill")) {
|
||||||
|
int input_pid = atoi(arguments);
|
||||||
|
if (input_pid < 0) {
|
||||||
|
printf("Bad input PID. Input number must not smaller than ZERO.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
kill_process(input_pid);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(input_str, "print")) {
|
||||||
|
print();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(input_str, "run")) {
|
||||||
|
int result = run(arguments);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if (input_str[0] == '\0');
|
||||||
|
else {
|
||||||
|
printf("Command not found.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kill_process(int pid) {
|
||||||
|
struct Block* block = NULL;
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) {
|
||||||
|
if (tasks[i].pid != pid) continue;
|
||||||
|
|
||||||
|
block = tasks[i].block;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (block == NULL) {
|
||||||
|
printf("Error: PID dosen't exist.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (block->last && block->last->pid < 0 && block->next && block->next->pid < 0) {
|
||||||
|
struct Block* free_block = block->last;
|
||||||
|
free_block->next = block->next->next;
|
||||||
|
free_block->size += block->size + block->next->size;
|
||||||
|
if (free_block->next) free_block->next->last = free_block;
|
||||||
|
free(block->next);
|
||||||
|
free(block);
|
||||||
|
}
|
||||||
|
else if (block->last && block->last->pid < 0) {
|
||||||
|
struct Block* free_block = block->last;
|
||||||
|
free_block->next = block->next;
|
||||||
|
free_block->size += block->size;
|
||||||
|
if (free_block->next) free_block->next->last = free_block;
|
||||||
|
free(block);
|
||||||
|
}
|
||||||
|
else if (block->next && block->next->pid < 0) {
|
||||||
|
struct Block* free_block = block;
|
||||||
|
free_block->size += block->next->size;
|
||||||
|
free_block->next = block->next->next;
|
||||||
|
free_block->pid = -1;
|
||||||
|
if (free_block->next) free_block->next->last = free_block;
|
||||||
|
free(block->next);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
block->pid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_wait_list();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
sys_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
sys_space->pid = -1;
|
||||||
|
sys_space->start = 0;
|
||||||
|
sys_space->size = sys_size;
|
||||||
|
sys_space->next = NULL;
|
||||||
|
sys_space->last = NULL;
|
||||||
|
|
||||||
|
usr_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
usr_space->pid = -1;
|
||||||
|
usr_space->start = sys_size;
|
||||||
|
usr_space->size = usr_size;
|
||||||
|
usr_space->next = NULL;
|
||||||
|
usr_space->last = NULL;
|
||||||
|
|
||||||
|
tasks = (struct Task*)malloc(MAX_NUM_TASKS * sizeof(struct Task));
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) tasks[i].pid = -1;
|
||||||
|
|
||||||
|
ask_match_method:
|
||||||
|
printf("Choose a matching method:\n 1. First Fit\n 2. Best Fit\n");
|
||||||
|
printf("choose> ");
|
||||||
|
scanf("%d", &match_method);
|
||||||
|
clean_stdin();
|
||||||
|
if (match_method != 1 && match_method != 2) {
|
||||||
|
printf("Bad input. Choose again.\n");
|
||||||
|
goto ask_match_method;
|
||||||
|
}
|
||||||
|
|
||||||
|
waitlist_begin = (struct Request*)malloc(sizeof(struct Request));
|
||||||
|
waitlist_end = waitlist_begin;
|
||||||
|
waitlist_begin->next = NULL;
|
||||||
|
waitlist_begin->size = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fork_process(int size) {
|
||||||
|
int pid;
|
||||||
|
int task_index = -1;
|
||||||
|
repeat:
|
||||||
|
last_pid++;
|
||||||
|
if (last_pid < 0) last_pid = 0;
|
||||||
|
pid = last_pid;
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) {
|
||||||
|
if (tasks[i].pid >= 0 && tasks[i].pid == pid) goto repeat;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < MAX_NUM_TASKS; i++) {
|
||||||
|
if (tasks[i].pid >= 0) continue;
|
||||||
|
task_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (task_index == -1) return -1;
|
||||||
|
|
||||||
|
size = preprocess_task_size(size);
|
||||||
|
tasks[task_index].size = size;
|
||||||
|
int start_loc = -1;
|
||||||
|
if (match_method == 1) start_loc = find_free_block_ff(size, &tasks[task_index].block);
|
||||||
|
else start_loc = find_free_block_bf(size, &tasks[task_index].block);
|
||||||
|
if (start_loc >= 0) {
|
||||||
|
tasks[task_index].start = start_loc;
|
||||||
|
tasks[task_index].pid = pid;
|
||||||
|
tasks[task_index].size = size;
|
||||||
|
tasks[task_index].block->pid = pid;
|
||||||
|
printf("Fork succeed. PID is %d . Block size is %d bits.\n", pid, size);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
printf("Fork failed. Out of Memory. Trying to push into wait list.\n");
|
||||||
|
queue_push(size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_free_block_ff(int size, struct Block** block_p) {
|
||||||
|
struct Block* now = usr_space;
|
||||||
|
int cnt = 1;
|
||||||
|
while (1) {
|
||||||
|
if (now == NULL) return -1;
|
||||||
|
if (now->pid < 0 && now->size >= size) break;
|
||||||
|
now = now->next;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
printf("Use %d times to find free block.\n", cnt);
|
||||||
|
*block_p = now;
|
||||||
|
if (now->size == size) return now->start;
|
||||||
|
struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
free_space->pid = -1;
|
||||||
|
free_space->last = now;
|
||||||
|
free_space->next = now->next;
|
||||||
|
free_space->size = now->size - size;
|
||||||
|
free_space->start = now->start + size;
|
||||||
|
|
||||||
|
now->pid = -2;
|
||||||
|
now->next = free_space;
|
||||||
|
now->size = size;
|
||||||
|
return now->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_free_block_bf(int size, struct Block** block_p) {
|
||||||
|
struct Block* now = usr_space, * best_block;
|
||||||
|
int best_size = 0x7fffffff;
|
||||||
|
int cnt = 1;
|
||||||
|
while (1) {
|
||||||
|
if (now == NULL) break;
|
||||||
|
if (now->pid < 0 && now->size >= size && best_size >= now->size) {
|
||||||
|
best_block = now;
|
||||||
|
best_size = now->size;
|
||||||
|
}
|
||||||
|
now = now->next;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
if (best_size == 0x7fffffff) return -1;
|
||||||
|
printf("Use %d times to find free block.\n", cnt);
|
||||||
|
*block_p = best_block;
|
||||||
|
if (best_block->size == size) return best_block->start;
|
||||||
|
struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
|
||||||
|
free_space->pid = -1;
|
||||||
|
free_space->last = best_block;
|
||||||
|
free_space->next = best_block->next;
|
||||||
|
free_space->size = best_block->size - size;
|
||||||
|
free_space->start = best_block->start + size;
|
||||||
|
|
||||||
|
best_block->pid = -2;
|
||||||
|
best_block->next = free_space;
|
||||||
|
best_block->size = size;
|
||||||
|
return best_block->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run(char* path) {
|
||||||
|
FILE* f = NULL;
|
||||||
|
f = fopen(path, "r+");
|
||||||
|
if (f == NULL) {
|
||||||
|
printf("Error: Invalid file path.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 0;
|
||||||
|
while (!feof(f) && result != -1) result = get_command(f);
|
||||||
|
fclose(f);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int preprocess_task_size(int size) {
|
||||||
|
int lower = size & 0x3ff;
|
||||||
|
if (lower == 0) return size;
|
||||||
|
int upper = size - lower;
|
||||||
|
size = upper + 0x400;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_push(int size) {
|
||||||
|
waitlist_begin->next = (struct Request*)malloc(sizeof(struct Request));
|
||||||
|
waitlist_begin = waitlist_begin->next;
|
||||||
|
waitlist_begin->next = NULL;
|
||||||
|
waitlist_begin->size = size;
|
||||||
|
waitlist_size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int queue_pop() {
|
||||||
|
if (!waitlist_size) {
|
||||||
|
printf("Wait list empty.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
struct Request* tmp = waitlist_end;
|
||||||
|
waitlist_end = waitlist_end->next;
|
||||||
|
free(tmp);
|
||||||
|
waitlist_size--;
|
||||||
|
return waitlist_end->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clean_stdin() {
|
||||||
|
int c;
|
||||||
|
do {
|
||||||
|
c = getchar();
|
||||||
|
} while (c != '\n' && c != EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute_wait_list() {
|
||||||
|
int size = -1, loop_num = waitlist_size;
|
||||||
|
for (int i = 0; i < loop_num; i++) {
|
||||||
|
size = queue_pop();
|
||||||
|
fork_process(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
char str[2][13] = { {" True"}, {" False"} };
|
||||||
|
char* s;
|
||||||
|
struct Block* p = sys_space;
|
||||||
|
printf("+----------------------------------------------------------------+\n");
|
||||||
|
printf("| System Space |\n");
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
printf("| Free | Begin | Size | End | PID |\n");
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
while (p != NULL) {
|
||||||
|
s = p->pid < 0 ? str[0] : str[1];
|
||||||
|
printf("|%s|%12d|%12d|%12d|%12d|\n", s, p->start, p->size, p->start + p->size - 1, p->pid);
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
printf("+----------------------------------------------------------------+\n\n");
|
||||||
|
|
||||||
|
p = usr_space;
|
||||||
|
printf("+----------------------------------------------------------------+\n");
|
||||||
|
printf("| User Space |\n");
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
printf("| Free | Begin | Size | End | PID |\n");
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
while (p != NULL) {
|
||||||
|
s = p->pid < 0 ? str[0] : str[1];
|
||||||
|
printf("|%s|%12d|%12d|%12d|%12d|\n", s, p->start, p->size, p->start + p->size - 1, p->pid);
|
||||||
|
printf("+------------+------------+------------+------------+------------+\n");
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
printf("+----------------------------------------------------------------+\n");
|
||||||
|
}
|
||||||
|
```
|
BIN
Lab/Lab4/source/21281280-柯劲帆-第4次实验.pdf
Normal file
BIN
Lab/Lab4/source/21281280-柯劲帆-第4次实验.pdf
Normal file
Binary file not shown.
BIN
Lab/Lab5/21281280-柯劲帆-第5次实验.pdf
Normal file
BIN
Lab/Lab5/21281280-柯劲帆-第5次实验.pdf
Normal file
Binary file not shown.
237
Lab/Lab5/code/main.c
Normal file
237
Lab/Lab5/code/main.c
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define REQUEST_LENGTH 100
|
||||||
|
#define DISK_TRACKS 200
|
||||||
|
|
||||||
|
double fcfs(int* requestArray, int requestLength, int headStart, int* outputArray);
|
||||||
|
double sstf(int* requestArray, int requestLength, int headStart, int* outputArray);
|
||||||
|
double scan(int* requestArray, int requestLength, int headStart, int* outputArray);
|
||||||
|
double cscan(int* requestArray, int requestLength, int headStart, int* outputArray);
|
||||||
|
double fscan(int* requestArray1, int requestLength1, int* requestArray2, int requestLength2, int headStart, int *outputArray);
|
||||||
|
|
||||||
|
|
||||||
|
// 生成随机磁道访问序列
|
||||||
|
void generateRandomSequence(int* sequence, int length) {
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
sequence[i] = rand() % DISK_TRACKS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印磁道访问顺序及平均寻道数
|
||||||
|
void printResults(const char* algorithmName, int* accessSequence, int length, double avgSeek) {
|
||||||
|
printf("%s Algorithm:\n", algorithmName);
|
||||||
|
printf("Visit Order: ");
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
printf("%d ", accessSequence[i]);
|
||||||
|
}
|
||||||
|
printf("\nAvg Seek Times: %.2f\n\n", avgSeek);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int requestSequence[REQUEST_LENGTH];
|
||||||
|
int *outputSequence[REQUEST_LENGTH];
|
||||||
|
int tempSequence[REQUEST_LENGTH];
|
||||||
|
double avgSeek;
|
||||||
|
int headStart = 50; // 假设的起始磁头位置
|
||||||
|
|
||||||
|
// 生成随机磁道访问序列
|
||||||
|
srand((unsigned)time(NULL));
|
||||||
|
generateRandomSequence(requestSequence, REQUEST_LENGTH);
|
||||||
|
|
||||||
|
// 测试 FCFS 算法
|
||||||
|
memcpy(tempSequence, requestSequence, sizeof(requestSequence));
|
||||||
|
avgSeek = fcfs(tempSequence, REQUEST_LENGTH, headStart, outputSequence);
|
||||||
|
printResults("FCFS", outputSequence, REQUEST_LENGTH, avgSeek);
|
||||||
|
|
||||||
|
// 测试 SSTF 算法
|
||||||
|
memcpy(tempSequence, requestSequence, sizeof(requestSequence));
|
||||||
|
avgSeek = sstf(tempSequence, REQUEST_LENGTH, headStart, outputSequence);
|
||||||
|
printResults("SSTF", outputSequence, REQUEST_LENGTH, avgSeek);
|
||||||
|
|
||||||
|
// 测试 SCAN 算法
|
||||||
|
memcpy(tempSequence, requestSequence, sizeof(requestSequence));
|
||||||
|
avgSeek = scan(tempSequence, REQUEST_LENGTH, headStart, outputSequence);
|
||||||
|
printResults("SCAN", outputSequence, REQUEST_LENGTH, avgSeek);
|
||||||
|
|
||||||
|
// 测试 CSCAN 算法
|
||||||
|
memcpy(tempSequence, requestSequence, sizeof(requestSequence));
|
||||||
|
avgSeek = cscan(tempSequence, REQUEST_LENGTH, headStart, outputSequence);
|
||||||
|
printResults("CSCAN", outputSequence, REQUEST_LENGTH, avgSeek);
|
||||||
|
|
||||||
|
// 测试 FSCAN 算法
|
||||||
|
// 注意:FSCAN需要两个队列,但为简化,在这里使用相同的队列两次
|
||||||
|
memcpy(tempSequence, requestSequence, sizeof(requestSequence));
|
||||||
|
avgSeek = fscan(requestSequence, REQUEST_LENGTH / 2, requestSequence + REQUEST_LENGTH / 2, REQUEST_LENGTH / 2, headStart, outputSequence);
|
||||||
|
printResults("FSCAN", outputSequence, REQUEST_LENGTH, avgSeek);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double fcfs(int* requestArray, int requestLength, int headStart, int* outputArray) {
|
||||||
|
int totalMovement = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
|
||||||
|
for (int i = 0; i < requestLength; i++) {
|
||||||
|
// 计算当前请求和磁头位置之间的距离
|
||||||
|
totalMovement += abs(requestArray[i] - currentPosition);
|
||||||
|
// 移动磁头到当前请求位置
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
// 记录移动过程
|
||||||
|
outputArray[i] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalMovement / requestLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
double sstf(int* requestArray, int requestLength, int headStart, int* outputArray) {
|
||||||
|
int totalSeekCount = 0;
|
||||||
|
int processedCount = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
int minDistance, closestIndex;
|
||||||
|
|
||||||
|
// 初始化一个数组来标记已处理的请求
|
||||||
|
int processed[REQUEST_LENGTH] = {0};
|
||||||
|
for (int i = 0; i < requestLength; i++) processed[i] = 0;
|
||||||
|
|
||||||
|
while (processedCount < requestLength) {
|
||||||
|
minDistance = 2147483647;
|
||||||
|
|
||||||
|
// 找到最近的请求
|
||||||
|
for (int i = 0; i < requestLength; i++) {
|
||||||
|
if (!processed[i] && abs(requestArray[i] - currentPosition) < minDistance) {
|
||||||
|
minDistance = abs(requestArray[i] - currentPosition);
|
||||||
|
closestIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理这个请求
|
||||||
|
totalSeekCount += minDistance;
|
||||||
|
currentPosition = requestArray[closestIndex];
|
||||||
|
processed[closestIndex] = 1;
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalSeekCount / requestLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
int compare(const void *a, const void *b) {
|
||||||
|
return (*(int*)a - *(int*)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
double scan(int* requestArray, int requestLength, int headStart, int* outputArray) {
|
||||||
|
int totalSeekCount = 0;
|
||||||
|
int processedCount = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
|
||||||
|
// 使用qsort进行排序
|
||||||
|
qsort(requestArray, requestLength, sizeof(int), compare);
|
||||||
|
|
||||||
|
// 找到起始位置最近的请求
|
||||||
|
int startIndex;
|
||||||
|
for (startIndex = 0; startIndex < requestLength; startIndex++) {
|
||||||
|
if (requestArray[startIndex] >= headStart) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先向上移动
|
||||||
|
for (int i = startIndex; i < requestLength; i++) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[i]);
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 然后向下移动
|
||||||
|
for (int i = startIndex - 1; i >= 0; i--) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[i]);
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalSeekCount / requestLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
double cscan(int* requestArray, int requestLength, int headStart, int* outputArray) {
|
||||||
|
int totalSeekCount = 0;
|
||||||
|
int processedCount = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
|
||||||
|
// 使用 qsort 进行排序
|
||||||
|
qsort(requestArray, requestLength, sizeof(int), compare);
|
||||||
|
|
||||||
|
// 找到起始位置最近的请求索引
|
||||||
|
int startIndex;
|
||||||
|
for (startIndex = 0; startIndex < requestLength; startIndex++) {
|
||||||
|
if (requestArray[startIndex] >= headStart) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先处理磁头上方的请求
|
||||||
|
for (int i = startIndex; i < requestLength; i++) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[i]);
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有必要,跳转到最低请求
|
||||||
|
if (startIndex != 0) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[0]);
|
||||||
|
currentPosition = requestArray[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 然后处理磁头下方的请求
|
||||||
|
for (int i = 0; i < startIndex; i++) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[i]);
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalSeekCount / requestLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
void processQueue(int* queue, int length, int* currentPosition, int* totalSeekCount, int* outputArray, int* processedCount) {
|
||||||
|
// 对队列进行排序
|
||||||
|
qsort(queue, length, sizeof(int), compare);
|
||||||
|
|
||||||
|
// 找到最接近当前磁头位置的请求
|
||||||
|
int i = 0;
|
||||||
|
while (i < length && queue[i] < *currentPosition) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先处理磁头位置之后(更高磁道号)的请求
|
||||||
|
for (int j = i; j < length; j++) {
|
||||||
|
*totalSeekCount += abs(*currentPosition - queue[j]);
|
||||||
|
*currentPosition = queue[j];
|
||||||
|
outputArray[(*processedCount)++] = queue[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再处理磁头位置之前(更低磁道号)的请求
|
||||||
|
for (int j = i - 1; j >= 0; j--) {
|
||||||
|
*totalSeekCount += abs(*currentPosition - queue[j]);
|
||||||
|
*currentPosition = queue[j];
|
||||||
|
outputArray[(*processedCount)++] = queue[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double fscan(int* requestArray1, int requestLength1, int* requestArray2, int requestLength2, int headStart, int* outputArray) {
|
||||||
|
int totalSeekCount = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
int processedCount = 0;
|
||||||
|
|
||||||
|
// 处理第一个队列
|
||||||
|
processQueue(requestArray1, requestLength1, ¤tPosition, &totalSeekCount, outputArray, &processedCount);
|
||||||
|
|
||||||
|
// 处理第二个队列
|
||||||
|
processQueue(requestArray2, requestLength2, ¤tPosition, &totalSeekCount, outputArray + requestLength1, &processedCount);
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalSeekCount / (requestLength1 + requestLength2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
380
Lab/Lab5/source/21281280-柯劲帆-第5次实验.md
Normal file
380
Lab/Lab5/source/21281280-柯劲帆-第5次实验.md
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
<h1><center>北京交通大学实验报告</center></h1>
|
||||||
|
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">课程名称</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">操作系统</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">实验题目</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">移动头磁盘调度算法模拟实现与比较</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">学号</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">21281280</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">姓名</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">柯劲帆</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">班级</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">物联网2101班</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">指导老师</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">何永忠</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">报告日期</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">2023年12月10日</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 1. 开发运行环境和工具
|
||||||
|
|
||||||
|
| 操作系统 | Linux内核版本 | 处理器 | GCC版本 |
|
||||||
|
| :---------: | :-----------------------: | :--------------------------------------: | :-------------------------------: |
|
||||||
|
| Deepin 20.9 | 5.18.17-amd64-desktop-hwe | Intel(R) Core(TM) i3-2330M CPU @ 2.20GHz | gcc (Uos 8.3.0.3-3+rebuild) 8.3.0 |
|
||||||
|
|
||||||
|
- **其他工具**:
|
||||||
|
- **编辑**:VSCode
|
||||||
|
- **编译和运行**:Terminal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 2. 实验过程、分析和结论
|
||||||
|
|
||||||
|
## 2.1. FCFS
|
||||||
|
|
||||||
|
```c
|
||||||
|
double fcfs(int* requestArray, int requestLength, int headStart, int* outputArray) {
|
||||||
|
int totalMovement = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
|
||||||
|
for (int i = 0; i < requestLength; i++) {
|
||||||
|
// 计算当前请求和磁头位置之间的距离
|
||||||
|
totalMovement += abs(requestArray[i] - currentPosition);
|
||||||
|
// 移动磁头到当前请求位置
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
// 记录移动过程
|
||||||
|
outputArray[i] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalMovement / requestLength;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
该部分测试输出为:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
FCFS Algorithm:
|
||||||
|
Visit Order: 176 32 118 25 69 54 180 129 112 63 176 107 109 74 186 89 31 31 189 177 90 25 179 103 64 110 24 192 121 12 75 144 49 70 138 151 29 168 166 48 54 175 191 50 193 101 121 26 54 11 119 144 96 167 142 1 12 41 102 93 45 153 132 146 151 67 27 121 83 197 173 71 195 64 189 47 31 197 182 157 158 114 33 102 193 197 155 175 188 89 21 27 94 151 73 33 4 110 137 173
|
||||||
|
Avg Seek Times: 66.65
|
||||||
|
```
|
||||||
|
|
||||||
|
FCFS算法非常简单,易于实现。然而,它并不是最优化的磁盘调度算法,因为它没有考虑磁头移动的最短路径,可能导致较长的平均寻道时间。这可能导致磁盘性能不佳,特别是在请求频繁变化的环境中。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.2. SSTF
|
||||||
|
|
||||||
|
```c
|
||||||
|
double sstf(int* requestArray, int requestLength, int headStart, int* outputArray) {
|
||||||
|
int totalSeekCount = 0;
|
||||||
|
int processedCount = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
int minDistance, closestIndex;
|
||||||
|
|
||||||
|
// 初始化一个数组来标记已处理的请求
|
||||||
|
int processed[REQUEST_LENGTH] = {0};
|
||||||
|
for (int i = 0; i < requestLength; i++) processed[i] = 0;
|
||||||
|
|
||||||
|
while (processedCount < requestLength) {
|
||||||
|
minDistance = 2147483647;
|
||||||
|
|
||||||
|
// 找到最近的请求
|
||||||
|
for (int i = 0; i < requestLength; i++) {
|
||||||
|
if (!processed[i] && abs(requestArray[i] - currentPosition) < minDistance) {
|
||||||
|
minDistance = abs(requestArray[i] - currentPosition);
|
||||||
|
closestIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理这个请求
|
||||||
|
totalSeekCount += minDistance;
|
||||||
|
currentPosition = requestArray[closestIndex];
|
||||||
|
processed[closestIndex] = 1;
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalSeekCount / requestLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
int compare(const void *a, const void *b) {
|
||||||
|
return (*(int*)a - *(int*)b);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
该部分测试输出为:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
SSTF Algorithm:
|
||||||
|
Visit Order: 50 49 48 47 45 41 33 33 32 31 31 31 29 27 27 26 25 25 24 21 12 12 11 4 1 54 54 54 63 64 64 67 69 70 71 73 74 75 83 89 89 90 93 94 96 101 102 102 103 107 109 110 110 112 114 118 119 121 121 121 129 132 137 138 142 144 144 146 151 151 151 153 155 157 158 166 167 168 173 173 175 175 176 176 177 179 180 182 186 188 189 189 191 192 193 193 195 197 197 197
|
||||||
|
Avg Seek Times: 2.45
|
||||||
|
```
|
||||||
|
|
||||||
|
相比于FCFS,SSTF算法在平均寻道时间上有显著提升。这是因为它通过选择最近的请求来减少每次磁头移动的距离,从而降低了总寻道距离。算法中使用 `abs(requestArray[i] - currentPosition)` 计算与当前磁头位置的距离,并选择最近的请求。这种方法更有效地利用了磁头的当前位置。
|
||||||
|
|
||||||
|
尽管SSTF在性能上优于FCFS,但它可能导致远离当前磁头位置的请求长时间等待,即“饥饿”问题。这在请求分布不均匀时尤其明显。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.3. SCAN
|
||||||
|
|
||||||
|
```c
|
||||||
|
int compare(const void *a, const void *b) {
|
||||||
|
return (*(int*)a - *(int*)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
double scan(int* requestArray, int requestLength, int headStart, int* outputArray) {
|
||||||
|
int totalSeekCount = 0;
|
||||||
|
int processedCount = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
|
||||||
|
outputArray = (int*)malloc(sizeof(int) * requestLength);
|
||||||
|
|
||||||
|
// 使用qsort进行排序
|
||||||
|
qsort(requestArray, requestLength, sizeof(int), compare);
|
||||||
|
|
||||||
|
// 找到起始位置最近的请求
|
||||||
|
int startIndex;
|
||||||
|
for (startIndex = 0; startIndex < requestLength; startIndex++) {
|
||||||
|
if (requestArray[startIndex] >= headStart) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先向上移动
|
||||||
|
for (int i = startIndex; i < requestLength; i++) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[i]);
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 然后向下移动
|
||||||
|
for (int i = startIndex - 1; i >= 0; i--) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[i]);
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalSeekCount / requestLength;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
该部分测试输出为:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
SCAN Algorithm:
|
||||||
|
Visit Order: 50 54 54 54 63 64 64 67 69 70 71 73 74 75 83 89 89 90 93 94 96 101 102 102 103 107 109 110 110 112 114 118 119 121 121 121 129 132 137 138 142 144 144 146 151 151 151 153 155 157 158 166 167 168 173 173 175 175 176 176 177 179 180 182 186 188 189 189 191 192 193 193 195 197 197 197 49 48 47 45 41 33 33 32 31 31 31 29 27 27 26 25 25 24 21 12 12 11 4 1
|
||||||
|
Avg Seek Times: 3.43
|
||||||
|
```
|
||||||
|
|
||||||
|
SCAN算法通过优化磁头移动的方向来减少寻道距离。它首先向一个方向移动,直到到达最远的请求,然后转向。 相比于SSTF,SCAN算法可以更好地避免饥饿问题。由于磁头最终会访问每个位置,因此所有的请求最终都会被服务。
|
||||||
|
|
||||||
|
SCAN算法提供了一种均衡的磁盘调度策略,既减少了平均寻道时间,又避免了长时间等待请求的饥饿问题。实验结果表明,虽然其平均寻道时间略高于SSTF,但在处理大量分散请求时,SCAN算法能提供更加稳定和公平的服务。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.4. CSCAN
|
||||||
|
|
||||||
|
```c
|
||||||
|
double cscan(int* requestArray, int requestLength, int headStart, int* outputArray) {
|
||||||
|
int totalSeekCount = 0;
|
||||||
|
int processedCount = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
|
||||||
|
outputArray = (int*)malloc(sizeof(int) * requestLength);
|
||||||
|
|
||||||
|
// 使用 qsort 进行排序
|
||||||
|
qsort(requestArray, requestLength, sizeof(int), compare);
|
||||||
|
|
||||||
|
// 找到起始位置最近的请求索引
|
||||||
|
int startIndex;
|
||||||
|
for (startIndex = 0; startIndex < requestLength; startIndex++) {
|
||||||
|
if (requestArray[startIndex] >= headStart) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先处理磁头上方的请求
|
||||||
|
for (int i = startIndex; i < requestLength; i++) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[i]);
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有必要,跳转到最低请求
|
||||||
|
if (startIndex != 0) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[0]);
|
||||||
|
currentPosition = requestArray[0];
|
||||||
|
processedCount = 1; // 重置为1,因为重新开始扫描
|
||||||
|
}
|
||||||
|
|
||||||
|
// 然后处理磁头下方的请求
|
||||||
|
for (int i = 0; i < startIndex; i++) {
|
||||||
|
totalSeekCount += abs(currentPosition - requestArray[i]);
|
||||||
|
currentPosition = requestArray[i];
|
||||||
|
outputArray[processedCount++] = currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalSeekCount / requestLength;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
该部分测试输出为:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
CSCAN Algorithm:
|
||||||
|
Visit Order: 50 54 54 54 63 64 64 67 69 70 71 73 74 75 83 89 89 90 93 94 96 101 102 102 103 107 109 110 110 112 114 118 119 121 121 121 129 132 137 138 142 144 144 146 151 151 151 153 155 157 158 166 167 168 173 173 175 175 176 176 177 179 180 182 186 188 189 189 191 192 193 193 195 197 197 197 1 4 11 12 12 21 24 25 25 26 27 27 29 31 31 31 32 33 33 41 45 47 48 49
|
||||||
|
Avg Seek Times: 3.91
|
||||||
|
```
|
||||||
|
|
||||||
|
循环扫描(CSCAN)算法类似于 SCAN 算法,但当磁头到达一个方向的最远端后,它会直接跳转到起始端,而不是改变方向。这种方式使得磁盘的磁头像循环一样移动,避免了SCAN算法中的反向移动。代码先处理磁头上方的请求,然后直接跳到最低的请求继续处理,直至结束。
|
||||||
|
|
||||||
|
CSCAN 提供了比 SCAN 更均匀的服务。由于磁头总是在一个方向上移动,所以它可以在相对固定的时间间隔内覆盖整个磁盘。尽管CSCAN可能有时候会导致更长的寻道距离(因为需要跳转到起点),但它保证了所有请求都会在有限时间内得到服务,从而减少了饥饿问题。CSCAN特别适用于请求分布不均匀的情况。它通过固定的方向移动,确保了即使在分布不均的情况下,每个请求最终都会被处理。尽管平均寻道时间可能略高,但它在保证服务公平性和预测性方面的优势使其成为许多场景下的理想选择。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.5. FSCAN
|
||||||
|
|
||||||
|
```c
|
||||||
|
void processRequests(int* requestArray, int requestLength, int* currentPosition, int* totalSeekCount, int* outputArray, int* processedCount) {
|
||||||
|
// 使用 qsort 进行排序
|
||||||
|
qsort(requestArray, requestLength, sizeof(int), compare);
|
||||||
|
|
||||||
|
// 处理所有请求
|
||||||
|
for (int i = 0; i < requestLength; i++) {
|
||||||
|
*totalSeekCount += abs(*currentPosition - requestArray[i]);
|
||||||
|
*currentPosition = requestArray[i];
|
||||||
|
outputArray[(*processedCount)++] = requestArray[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double fscan(int* requestArray1, int requestLength1, int* requestArray2, int requestLength2, int headStart, int *outputArray) {
|
||||||
|
int totalSeekCount = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
int processedCount = 0;
|
||||||
|
|
||||||
|
outputArray = (int*)malloc(sizeof(int) * (requestLength1 + requestLength2));
|
||||||
|
|
||||||
|
// 处理第一个队列
|
||||||
|
processRequests(requestArray1, requestLength1, ¤tPosition, &totalSeekCount, outputArray, &processedCount);
|
||||||
|
|
||||||
|
// 处理第二个队列
|
||||||
|
processRequests(requestArray2, requestLength2, ¤tPosition, &totalSeekCount, outputArray, &processedCount);
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalSeekCount / (requestLength1 + requestLength2);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
该部分测试输出为:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
FSCAN Algorithm:
|
||||||
|
Visit Order: 50 54 54 54 63 64 69 70 74 75 89 90 101 103 107 109 110 112 118 121 121 129 138 144 151 166 168 175 176 176 177 179 180 186 189 191 192 193 49 48 32 31 31 29 26 25 25 24 12 11 158 166 167 168 173 173 175 175 176 176 177 179 180 182 186 188 189 189 191 192 193 193 195 197 197 197 1 4 11 12 12 21 24 25 25 26 27 27 29 31 31 31 32 33 33 41 45 47 48 49
|
||||||
|
Avg Seek Times: 7.07
|
||||||
|
```
|
||||||
|
|
||||||
|
FSCAN通过将请求分成两个队列来减少磁头移动次数。这样,它可以在处理当前队列时不受新请求的干扰。由于FSCAN总是处理完整个队列,它可以有效预防饥饿问题。每个请求最终都会被处理。分开处理两个队列可以提高处理效率。在处理一个队列时,磁头不需要反复移动以应对新进的请求。
|
||||||
|
|
||||||
|
测试输出显示平均寻道时间为7.07。这个数值相比其他算法较高,可能是因为在处理一个队列时,磁头需要移动到另一个队列的起始位置,导致额外的寻道时间。
|
||||||
|
|
||||||
|
FSCAN特别适合于请求量大且需要公平处理的场景。它通过分开处理不同的请求队列,确保了长期运行下的稳定性和公平性。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.5. MAIN
|
||||||
|
|
||||||
|
```c
|
||||||
|
void processQueue(int* queue, int length, int* currentPosition, int* totalSeekCount, int* outputArray, int* processedCount) {
|
||||||
|
// 对队列进行排序
|
||||||
|
qsort(queue, length, sizeof(int), compare);
|
||||||
|
|
||||||
|
// 找到最接近当前磁头位置的请求
|
||||||
|
int i = 0;
|
||||||
|
while (i < length && queue[i] < *currentPosition) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先处理磁头位置之后(更高磁道号)的请求
|
||||||
|
for (int j = i; j < length; j++) {
|
||||||
|
*totalSeekCount += abs(*currentPosition - queue[j]);
|
||||||
|
*currentPosition = queue[j];
|
||||||
|
outputArray[(*processedCount)++] = queue[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再处理磁头位置之前(更低磁道号)的请求
|
||||||
|
for (int j = i - 1; j >= 0; j--) {
|
||||||
|
*totalSeekCount += abs(*currentPosition - queue[j]);
|
||||||
|
*currentPosition = queue[j];
|
||||||
|
outputArray[(*processedCount)++] = queue[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double fscan(int* requestArray1, int requestLength1, int* requestArray2, int requestLength2, int headStart, int* outputArray) {
|
||||||
|
int totalSeekCount = 0;
|
||||||
|
int currentPosition = headStart;
|
||||||
|
int processedCount = 0;
|
||||||
|
|
||||||
|
// 处理第一个队列
|
||||||
|
processQueue(requestArray1, requestLength1, ¤tPosition, &totalSeekCount, outputArray, &processedCount);
|
||||||
|
|
||||||
|
// 处理第二个队列
|
||||||
|
processQueue(requestArray2, requestLength2, ¤tPosition, &totalSeekCount, outputArray + requestLength1, &processedCount);
|
||||||
|
|
||||||
|
// 计算平均寻道数
|
||||||
|
return (double)totalSeekCount / (requestLength1 + requestLength2);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 结论
|
||||||
|
|
||||||
|
| 算法 | 平均寻道数1 | 平均寻道数2 |
|
||||||
|
| ----- | ----------- | ----------- |
|
||||||
|
| FCFS | 66.65 | 60.75 |
|
||||||
|
| SSTF | 2.45 | 2.49 |
|
||||||
|
| SCAN | 3.43 | 3.48 |
|
||||||
|
| CSCAN | 3.91 | 3.97 |
|
||||||
|
| FSCAN | 7.07 | 7.34 |
|
||||||
|
|
||||||
|
从实验数据中,我们可以看到不同磁盘调度算法在平均寻道数方面的表现差异。以下是对各算法性能的总结和分析:
|
||||||
|
|
||||||
|
**FCFS (先来先服务)**
|
||||||
|
|
||||||
|
- **平均寻道数:** 66.65 和 60.75
|
||||||
|
- **分析:** FCFS算法因其简单性在平均寻道数上表现最差。由于它仅基于请求到达的顺序,没有考虑磁头移动的最优化,因此导致了较高的寻道数。
|
||||||
|
|
||||||
|
**SSTF (最短寻道时间优先)**
|
||||||
|
|
||||||
|
- **平均寻道数:** 2.45 和 2.49
|
||||||
|
- **分析:** SSTF算法大幅改进了寻道性能,因为它总是选择距离当前磁头位置最近的请求。这种策略显著减少了磁头的移动距离,从而降低了平均寻道数。
|
||||||
|
|
||||||
|
**SCAN (扫描)**
|
||||||
|
|
||||||
|
- **平均寻道数:** 3.43 和 3.48
|
||||||
|
- **分析:** SCAN算法的表现优于FCFS,略逊于SSTF。它通过模仿电梯运行,从一端移动到另一端,避免了频繁的方向改变,从而实现了较低的寻道数。
|
||||||
|
|
||||||
|
**CSCAN (循环扫描)**
|
||||||
|
|
||||||
|
- **平均寻道数:** 3.91 和 3.97
|
||||||
|
- **分析:** CSCAN算法提供了一个循环的扫描机制,避免了SCAN中的反向移动,但其平均寻道数略高于SCAN。这可能是因为在达到一端后需要跳转到另一端,导致了额外的寻道时间。
|
||||||
|
|
||||||
|
**FSCAN (FIFO扫描)**
|
||||||
|
|
||||||
|
- **平均寻道数:** 7.07 和 7.34
|
||||||
|
- **分析:** FSCAN算法在所有测试算法中平均寻道数次高。虽然它通过使用两个队列来优化长期的公平性和稳定性,但在单次运行中,由于需要在两个队列间切换,可能导致较高的寻道数。
|
||||||
|
|
||||||
|
**总体观察**
|
||||||
|
|
||||||
|
- 在这些算法中,**SSTF** 和 **SCAN** 在平均寻道数方面表现最佳,提供了较好的性能与效率平衡。
|
||||||
|
- **FCFS** 由于其简单性,在寻道数方面表现最差。
|
||||||
|
- **CSCAN** 和 **FSCAN** 虽然在某些场景下可能更合适,但在这组数据中它们的平均寻道数相对较高。
|
||||||
|
|
||||||
|
这些结果显示了在不同的磁盘调度策略下,性能和效率之间的权衡。选择最合适的算法取决于具体的应用场景和对性能、效率以及公平性的不同需求。
|
BIN
Lab/Lab6/21281280-柯劲帆-第6次实验.pdf
Normal file
BIN
Lab/Lab6/21281280-柯劲帆-第6次实验.pdf
Normal file
Binary file not shown.
BIN
Lab/Lab6/code/KJF_disk.img
Normal file
BIN
Lab/Lab6/code/KJF_disk.img
Normal file
Binary file not shown.
3
Lab/Lab6/code/data.txt
Normal file
3
Lab/Lab6/code/data.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
x86 (also known as 80x86 or the 8086 family) is a family of complex instruction set computer (CISC) instruction set architectures initially developed by Intel based on the Intel 8086 microprocessor and its 8088 variant. The 8086 was introduced in 1978 as a fully 16-bit extension of Intel's 8-bit 8080 microprocessor, with memory segmentation as a solution for addressing more memory than can be covered by a plain 16-bit address. The term "x86" came into being because the names of several successors to Intel's 8086 processor end in "86", including the 80186, 80286, 80386 and 80486 processors.
|
||||||
|
The Intel x86 processor uses complex instruction set computer (CISC) architecture, which means there is a modest number of special-purpose registers instead of large quantities of general-purpose registers. It also means that complex special-purpose instructions will predominate.
|
||||||
|
The x86 processor traces its heritage at least as far back as the 8-bit Intel 8080 processor. Many peculiarities in the x86 instruction set are due to the backward compatibility with that processor (and with its Zilog Z-80 variant).
|
378
Lab/Lab6/code/main.c
Normal file
378
Lab/Lab6/code/main.c
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#define BS_jmpBoot_Offset 0x00 // 跳转指令偏移
|
||||||
|
#define BS_jmpBoot_Len 3 // 跳转指令长度
|
||||||
|
#define BS_OEMName_Offset 0x03 // 厂商名称偏移
|
||||||
|
#define BS_OEMName_Len 8 // 厂商名称长度
|
||||||
|
#define BPB_BytsPerSec_Offset 0x0B // 每扇区字节数偏移
|
||||||
|
#define BPB_BytsPerSec_Len 2 // 每扇区字节数长度
|
||||||
|
#define BPB_SecPerClus_Offset 0x0D // 每簇扇区数偏移
|
||||||
|
#define BPB_SecPerClus_Len 1 // 每簇扇区数长度
|
||||||
|
#define BPB_RsvdSecCnt_Offset 0x0E // 保留扇区数 (引导扇区的扇区数)偏移
|
||||||
|
#define BPB_RsvdSecCnt_Len 2 // 保留扇区数 (引导扇区的扇区数)长度
|
||||||
|
#define BPB_NumFATs_Offset 0x10 // FAT的份数偏移
|
||||||
|
#define BPB_NumFATs_Len 1 // FAT的份数长度
|
||||||
|
#define BPB_RootEntCnt_Offset 0x11 // 根目录可容纳的目录项数偏移
|
||||||
|
#define BPB_RootEntCnt_Len 2 // 根目录可容纳的目录项数长度
|
||||||
|
#define BPB_TotSec16_Offset 0x13 // 扇区总数偏移
|
||||||
|
#define BPB_TotSec16_Len 2 // 扇区总数长度
|
||||||
|
#define BPB_Media_Offset 0x15 // 介质描述符偏移
|
||||||
|
#define BPB_Media_Len 1 // 介质描述符长度
|
||||||
|
#define BPB_FATSz16_Offset 0x16 // 每个FAT表扇区数偏移
|
||||||
|
#define BPB_FATSz16_Len 2 // 每个FAT表扇区数长度
|
||||||
|
#define BPB_SecPerTrk_Offset 0x18 // 每磁道扇区数偏移
|
||||||
|
#define BPB_SecPerTrk_Len 2 // 每磁道扇区数长度
|
||||||
|
#define BPB_NumHeads_Offset 0x1A // 磁头数偏移
|
||||||
|
#define BPB_NumHeads_Len 2 // 磁头数长度
|
||||||
|
#define BPB_HiddSec_Offset 0x1C // 隐藏扇区数偏移
|
||||||
|
#define BPB_HiddSec_Len 4 // 隐藏扇区数长度
|
||||||
|
#define BPB_TotSec32_Offset 0x20 // 偏移 如果BPB_TotSec16是0,由这个值记录扇区数
|
||||||
|
#define BPB_TotSec32_Len 4 // 长度 如果BPB_TotSec16是0,由这个值记录扇区数
|
||||||
|
#define BS_DrvNum_Offset 0x24 // int 13h的驱动器号偏移
|
||||||
|
#define BS_DrvNum_Len 1 // int 13h的驱动器号长度
|
||||||
|
#define BS_Reservedl_Offset 0x25 // 偏移 未使用
|
||||||
|
#define BS_Reservedl_Len 1 // 长度 未使用
|
||||||
|
#define BS_BootSig_Offset 0x26 // 扩展引导标记偏移
|
||||||
|
#define BS_BootSig_Len 1 // 扩展引导标记长度
|
||||||
|
#define BS_VolID_Offset 0x27 // 卷序列号偏移
|
||||||
|
#define BS_VolID_Len 4 // 卷序列号长度
|
||||||
|
#define BS_VolLab_Offset 0x2B // 卷标偏移
|
||||||
|
#define BS_VolLab_Len 11 // 卷标长度
|
||||||
|
#define BS_FileSysType_Offset 0x36 // 文件系统类型偏移
|
||||||
|
#define BS_FileSysType_Len 8 // 文件系统类型长度
|
||||||
|
#define DBR_BootCode_Offset 0x3E // 引导代码及其他偏移
|
||||||
|
#define DBR_BootCode_Len 448 // 引导代码及其他长度
|
||||||
|
#define DBR_EndMark_Offset 0x1FE // 结束标志偏移
|
||||||
|
#define DBR_EndMark_Len 2 // 结束标志长度
|
||||||
|
#define DBR_EndMark 0xAA55 // 结束标志
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
short BytsPerSec; // 每扇区字节数
|
||||||
|
char SecPerClus; // 每簇扇区数
|
||||||
|
short RsvdSecCnt; // 保留扇区数 (引导扇区的扇区数)
|
||||||
|
char NumFATs; // FAT的份数
|
||||||
|
short RootEntCnt; // 根目录可容纳的目录项数
|
||||||
|
short TotSec16; // 扇区总数
|
||||||
|
char Media; // 介质描述符
|
||||||
|
short FATSz16; // 每个FAT表扇区数
|
||||||
|
short SecPerTrk; // 每磁道扇区数
|
||||||
|
short NumHeads; // 磁头数
|
||||||
|
int HiddSec; // 隐藏扇区数
|
||||||
|
int TotSec32; // 替代扇区数
|
||||||
|
char DrvNum; // int 13h的驱动器号
|
||||||
|
char Reservedl; // 未使用
|
||||||
|
char BootSig; // 扩展引导标记
|
||||||
|
int VolID; // 卷序列号
|
||||||
|
int TotalSize; // 总磁盘大小
|
||||||
|
int current_dir; // 当前目录的首地址
|
||||||
|
} DISK;
|
||||||
|
|
||||||
|
|
||||||
|
DISK init_disk_attr() {
|
||||||
|
DISK disk;
|
||||||
|
disk.BytsPerSec = 0x0200;
|
||||||
|
disk.SecPerClus = 0x01;
|
||||||
|
disk.RsvdSecCnt = 0x0001;
|
||||||
|
disk.NumFATs = 0x01;
|
||||||
|
disk.RootEntCnt = 0x0200;
|
||||||
|
disk.TotSec16 = 0x2000;
|
||||||
|
disk.Media = 0xf8;
|
||||||
|
disk.FATSz16 = 0x0020;
|
||||||
|
disk.SecPerTrk = 0x0020;
|
||||||
|
disk.NumHeads = 0x0040;
|
||||||
|
disk.HiddSec = 0x00000000;
|
||||||
|
disk.TotSec32 = 0x00000000;
|
||||||
|
disk.DrvNum = 0x80;
|
||||||
|
disk.Reservedl = 0x00;
|
||||||
|
disk.BootSig = 0x29;
|
||||||
|
disk.VolID = 0x00000000;
|
||||||
|
disk.TotalSize = 0x400000;
|
||||||
|
disk.current_dir = 0x4200;
|
||||||
|
return disk;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct tm get_time() {
|
||||||
|
struct timeval tv;
|
||||||
|
struct timezone tz;
|
||||||
|
struct tm *t;
|
||||||
|
|
||||||
|
gettimeofday(&tv, &tz);
|
||||||
|
t = localtime(&tv.tv_sec);
|
||||||
|
return *t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void init_file_system(char disk_name[13], DISK disk_attr) {
|
||||||
|
FILE* fp = fopen(disk_name, "wb");
|
||||||
|
// 跳转指令
|
||||||
|
fseek(fp, BS_jmpBoot_Offset, 0);
|
||||||
|
char jmpBoot[BS_jmpBoot_Len] = { 0xEB, 0x3C, 0x90 };
|
||||||
|
fwrite(jmpBoot, 1, BS_jmpBoot_Len, fp);
|
||||||
|
|
||||||
|
// 厂商名称
|
||||||
|
fseek(fp, BS_OEMName_Offset, 0);
|
||||||
|
char OEMName[BS_OEMName_Len] = { 'K', 'e', 'J', 'F', ' ', ' ', ' ', ' ' };
|
||||||
|
fwrite(OEMName, 1, BS_OEMName_Len, fp);
|
||||||
|
|
||||||
|
// 每扇区字节数
|
||||||
|
fseek(fp, BPB_BytsPerSec_Offset, 0);
|
||||||
|
fwrite(&disk_attr.BytsPerSec, BPB_BytsPerSec_Len, 1, fp);
|
||||||
|
|
||||||
|
// 每簇扇区数
|
||||||
|
fseek(fp, BPB_SecPerClus_Offset, 0);
|
||||||
|
fwrite(&disk_attr.SecPerClus, BPB_SecPerClus_Len, 1, fp);
|
||||||
|
|
||||||
|
// 保留扇区数 (引导扇区的扇区数)
|
||||||
|
fseek(fp, BPB_RsvdSecCnt_Offset, 0);
|
||||||
|
fwrite(&disk_attr.RsvdSecCnt, BPB_RsvdSecCnt_Len, 1, fp);
|
||||||
|
|
||||||
|
// FAT的份数
|
||||||
|
fseek(fp, BPB_NumFATs_Offset, 0);
|
||||||
|
fwrite(&disk_attr.NumFATs, BPB_NumFATs_Len, 1, fp);
|
||||||
|
|
||||||
|
// 根目录可容纳的目录项数
|
||||||
|
fseek(fp, BPB_RootEntCnt_Offset, 0);
|
||||||
|
fwrite(&disk_attr.RootEntCnt, BPB_RootEntCnt_Len, 1, fp);
|
||||||
|
|
||||||
|
// 扇区总数
|
||||||
|
fseek(fp, BPB_TotSec16_Offset, 0);
|
||||||
|
fwrite(&disk_attr.TotSec16, BPB_TotSec16_Len, 1, fp);
|
||||||
|
|
||||||
|
// 介质描述符
|
||||||
|
fseek(fp, BPB_Media_Offset, 0);
|
||||||
|
fwrite(&disk_attr.Media, BPB_Media_Len, 1, fp);
|
||||||
|
|
||||||
|
// 每个FAT表扇区数
|
||||||
|
fseek(fp, BPB_FATSz16_Offset, 0);
|
||||||
|
fwrite(&disk_attr.FATSz16, BPB_FATSz16_Len, 1, fp);
|
||||||
|
|
||||||
|
// 每磁道扇区数
|
||||||
|
fseek(fp, BPB_SecPerTrk_Offset, 0);
|
||||||
|
fwrite(&disk_attr.SecPerTrk, BPB_SecPerTrk_Len, 1, fp);
|
||||||
|
|
||||||
|
// 磁头数
|
||||||
|
fseek(fp, BPB_NumHeads_Offset, 0);
|
||||||
|
fwrite(&disk_attr.NumHeads, BPB_NumHeads_Len, 1, fp);
|
||||||
|
|
||||||
|
// 隐藏扇区数
|
||||||
|
fseek(fp, BPB_HiddSec_Offset, 0);
|
||||||
|
fwrite(&disk_attr.HiddSec, BPB_HiddSec_Len, 1, fp);
|
||||||
|
|
||||||
|
// 替代扇区数
|
||||||
|
fseek(fp, BPB_TotSec32_Offset, 0);
|
||||||
|
fwrite(&disk_attr.TotSec32, BPB_TotSec32_Len, 1, fp);
|
||||||
|
|
||||||
|
// int 13h的驱动器号
|
||||||
|
fseek(fp, BS_DrvNum_Offset, 0);
|
||||||
|
fwrite(&disk_attr.DrvNum, BS_DrvNum_Len, 1, fp);
|
||||||
|
|
||||||
|
// 未使用
|
||||||
|
fseek(fp, BS_Reservedl_Offset, 0);
|
||||||
|
fwrite(&disk_attr.Reservedl, BS_Reservedl_Len, 1, fp);
|
||||||
|
|
||||||
|
// 扩展引导标记
|
||||||
|
fseek(fp, BS_BootSig_Offset, 0);
|
||||||
|
fwrite(&disk_attr.BootSig, BS_BootSig_Len, 1, fp);
|
||||||
|
|
||||||
|
// 卷序列号
|
||||||
|
fseek(fp, BS_VolID_Offset, 0);
|
||||||
|
fwrite(&disk_attr.VolID, BS_VolID_Len, 1, fp);
|
||||||
|
|
||||||
|
// 卷标
|
||||||
|
fseek(fp, BS_VolLab_Offset, 0);
|
||||||
|
char VolLab[BS_VolLab_Len] = {'K', 'e', 'J', 'i', 'n', 'g', 'f', 'a', 'n', ' ', ' '};
|
||||||
|
fwrite(VolLab, 1, BS_VolLab_Len, fp);
|
||||||
|
|
||||||
|
// 文件系统类型
|
||||||
|
fseek(fp, BS_FileSysType_Offset, 0);
|
||||||
|
char FileSysType[BS_FileSysType_Len] = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '};
|
||||||
|
fwrite(FileSysType, 1, BS_FileSysType_Len, fp);
|
||||||
|
|
||||||
|
// 引导代码等
|
||||||
|
fseek(fp, DBR_BootCode_Offset, 0);
|
||||||
|
char BootCode[DBR_BootCode_Len] = { 0 };
|
||||||
|
fwrite(BootCode, 1, DBR_BootCode_Len, fp);
|
||||||
|
|
||||||
|
// 结束标志
|
||||||
|
fseek(fp, DBR_EndMark_Offset, 0);
|
||||||
|
short EndMark = DBR_EndMark;
|
||||||
|
fwrite(&EndMark, DBR_EndMark_Len, 1, fp);
|
||||||
|
|
||||||
|
// FAT分区表
|
||||||
|
fseek(fp, 0x0200, 0);
|
||||||
|
int FAT_Len = disk_attr.FATSz16 * disk_attr.BytsPerSec * disk_attr.NumFATs; // 每个FAT表扇区数 * 扇区字节数 * FAT的份数
|
||||||
|
char* FAT_data = (char*)malloc(sizeof(char) * FAT_Len);
|
||||||
|
fwrite(FAT_data, 1, FAT_Len, fp);
|
||||||
|
|
||||||
|
// DATA段
|
||||||
|
fseek(fp, 0x0200 + FAT_Len, 0);
|
||||||
|
int DATA_Len = disk_attr.TotalSize - 0x0200 - FAT_Len;
|
||||||
|
char* DATA_data = (char*)malloc(sizeof(char) * DATA_Len);
|
||||||
|
fwrite(DATA_data, 1, DATA_Len, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned short find_free_blocks(DISK disk_attr, FILE *fp) {
|
||||||
|
unsigned short begin = 0x200;
|
||||||
|
unsigned short end = disk_attr.FATSz16 * disk_attr.BytsPerSec;
|
||||||
|
unsigned short ans = 0x06;
|
||||||
|
while (ans < end) {
|
||||||
|
fseek(fp, begin + ans, 0);
|
||||||
|
char index[5] = { 0 };
|
||||||
|
fread(index, 1, 4, fp);
|
||||||
|
if (!index[0] && !index[1] && !index[2] && !index[3]) break;
|
||||||
|
ans += 2;
|
||||||
|
}
|
||||||
|
if (ans >= end) return 0xFFFF;
|
||||||
|
return ans / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mkdir(char dir_name[11], char disk_name[13], DISK disk_attr) {
|
||||||
|
FILE* fp = fopen(disk_name, "rb+");
|
||||||
|
unsigned short dir_firstBlockNum = find_free_blocks(disk_attr, fp);
|
||||||
|
if (dir_firstBlockNum == 0xFFFF) return -1;
|
||||||
|
|
||||||
|
fseek(fp, 0x200 + dir_firstBlockNum * 2, 0);
|
||||||
|
short new_index = 0xFFFF;
|
||||||
|
fwrite(&new_index, 2, 1, fp);
|
||||||
|
|
||||||
|
int start_byte = disk_attr.current_dir;
|
||||||
|
int byte_line_num = 0;
|
||||||
|
while (byte_line_num < disk_attr.BytsPerSec) {
|
||||||
|
fseek(fp, start_byte + byte_line_num, 0);
|
||||||
|
int byte_line[4] = { 0 };
|
||||||
|
fread(byte_line, 4, 3, fp);
|
||||||
|
if (!byte_line[0] && !byte_line[1] && !byte_line[2]) break;
|
||||||
|
byte_line_num += 0x20;
|
||||||
|
}
|
||||||
|
if (byte_line_num >= disk_attr.BytsPerSec) return -1;
|
||||||
|
fseek(fp, start_byte + byte_line_num, 0);
|
||||||
|
fwrite(dir_name, 1, 11, fp);
|
||||||
|
short dir_attr_byte = 0b00010000;
|
||||||
|
fwrite(&dir_attr_byte, 1, 1, fp);
|
||||||
|
|
||||||
|
short dir_reserved_byte[6] = { 0 };
|
||||||
|
fwrite(dir_reserved_byte, 2, 5, fp);
|
||||||
|
|
||||||
|
struct tm time = get_time();
|
||||||
|
short dir_time_byte = time.tm_hour * 2048 + time.tm_min * 32 + time.tm_sec / 2;
|
||||||
|
fwrite(&dir_time_byte, 2, 1, fp);
|
||||||
|
short dir_date_byte = (time.tm_year + 1900 - 1980) * 512 + time.tm_mon * 32 + time.tm_mday;
|
||||||
|
fwrite(&dir_date_byte, 2, 1, fp);
|
||||||
|
fwrite(&dir_firstBlockNum, 2, 1, fp);
|
||||||
|
short dir_size = disk_attr.BytsPerSec * disk_attr.SecPerClus;
|
||||||
|
fwrite(&dir_size, 2, 1, fp);
|
||||||
|
|
||||||
|
int new_block = 0x7800 + disk_attr.BytsPerSec * disk_attr.SecPerClus * dir_firstBlockNum;
|
||||||
|
fseek(fp, new_block, 0);
|
||||||
|
char dot[11] = { '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
|
||||||
|
fwrite(dot, 1, 11, fp);
|
||||||
|
fwrite(&dir_attr_byte, 1, 1, fp);
|
||||||
|
fwrite(dir_reserved_byte, 2, 5, fp);
|
||||||
|
fwrite(&dir_time_byte, 2, 1, fp);
|
||||||
|
fwrite(&dir_date_byte, 2, 1, fp);
|
||||||
|
short dir_oriBlock_byte = 0;
|
||||||
|
fwrite(&dir_oriBlock_byte, 2, 1, fp);
|
||||||
|
unsigned int dir_oriSize = 0;
|
||||||
|
fwrite(&dir_oriSize, 4, 1, fp);
|
||||||
|
|
||||||
|
fseek(fp, new_block + 0x20, 0);
|
||||||
|
char dotdot[11] = { '.', '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
|
||||||
|
fwrite(dotdot, 1, 11, fp);
|
||||||
|
fwrite(&dir_attr_byte, 1, 1, fp);
|
||||||
|
fwrite(dir_reserved_byte, 2, 5, fp);
|
||||||
|
short dir_oriTime_byte = 0;
|
||||||
|
fwrite(&dir_oriTime_byte, 2, 1, fp);
|
||||||
|
short dir_oriDate_byte = (1970 - 1980 + 1900) * 512 + 1 * 32 + 1;
|
||||||
|
fwrite(&dir_oriDate_byte, 2, 1, fp);
|
||||||
|
fwrite(&dir_oriBlock_byte, 2, 1, fp);
|
||||||
|
fwrite(&dir_oriSize, 4, 1, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int touch(char file_name[11], char disk_name[13], DISK disk_attr) {
|
||||||
|
FILE* contentFile = fopen("./data.txt", "r");
|
||||||
|
char *content = (char*)malloc(2000 * sizeof(char));
|
||||||
|
fread(content, 1, 2000, contentFile);
|
||||||
|
fclose(contentFile);
|
||||||
|
FILE* fp = fopen(disk_name, "rb+");
|
||||||
|
int file_blockNum = strlen(content) / (disk_attr.BytsPerSec * disk_attr.SecPerClus) + 1;
|
||||||
|
unsigned short* index = (short*)malloc(sizeof(short) * file_blockNum);
|
||||||
|
for (int i = 0; i < file_blockNum; i++) {
|
||||||
|
index[i] = find_free_blocks(disk_attr, fp);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < file_blockNum - 1; i++) {
|
||||||
|
fseek(fp, 0x200 + index[i] * 2, 0);
|
||||||
|
fwrite(&index[i + 1], 2, 1, fp);
|
||||||
|
}
|
||||||
|
fseek(fp, 0x200 + index[file_blockNum - 1] * 2, 0);
|
||||||
|
short last_index = 0xFFFF;
|
||||||
|
fwrite(&last_index, 2, 1, fp);
|
||||||
|
|
||||||
|
int start_byte = disk_attr.current_dir;
|
||||||
|
int byte_line_num = 0;
|
||||||
|
while (byte_line_num < disk_attr.BytsPerSec) {
|
||||||
|
fseek(fp, start_byte + byte_line_num, 0);
|
||||||
|
int byte_line[4] = { 0 };
|
||||||
|
fread(byte_line, 4, 3, fp);
|
||||||
|
if (!byte_line[0] && !byte_line[1] && !byte_line[2]) break;
|
||||||
|
byte_line_num += 0x20;
|
||||||
|
}
|
||||||
|
if (byte_line_num >= disk_attr.BytsPerSec) return -1;
|
||||||
|
fseek(fp, start_byte + byte_line_num, 0);
|
||||||
|
fwrite(file_name, 1, 11, fp);
|
||||||
|
short file_attr_byte = 0b00000000;
|
||||||
|
fwrite(&file_attr_byte, 1, 1, fp);
|
||||||
|
|
||||||
|
short file_reserved_byte[6] = { 0 };
|
||||||
|
fwrite(file_reserved_byte, 2, 5, fp);
|
||||||
|
|
||||||
|
struct tm time = get_time();
|
||||||
|
short file_time_byte = time.tm_hour * 2048 + time.tm_min * 32 + time.tm_sec / 2;
|
||||||
|
fwrite(&file_time_byte, 2, 1, fp);
|
||||||
|
short file_date_byte = (time.tm_year + 1900 - 1980) * 512 + time.tm_mon * 32 + time.tm_mday;
|
||||||
|
fwrite(&file_date_byte, 2, 1, fp);
|
||||||
|
fwrite(&index[0], 2, 1, fp);
|
||||||
|
unsigned int file_size = strlen(content);
|
||||||
|
fwrite(&file_size, 4, 1, fp);
|
||||||
|
|
||||||
|
for (int i = 0; i < file_blockNum; i++) {
|
||||||
|
int new_block = 0x7800 + disk_attr.BytsPerSec * disk_attr.SecPerClus * index[i];
|
||||||
|
fseek(fp, new_block, 0);
|
||||||
|
fwrite(content,
|
||||||
|
file_size > disk_attr.BytsPerSec * disk_attr.SecPerClus ? disk_attr.BytsPerSec * disk_attr.SecPerClus : file_size,
|
||||||
|
1,
|
||||||
|
fp
|
||||||
|
);
|
||||||
|
content += disk_attr.BytsPerSec * disk_attr.SecPerClus;
|
||||||
|
file_size -= disk_attr.BytsPerSec * disk_attr.SecPerClus;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
char disk_name[13] = "KJF_disk.img";
|
||||||
|
DISK disk_attr = init_disk_attr();
|
||||||
|
init_file_system(disk_name, disk_attr);
|
||||||
|
|
||||||
|
// char dir_name[11] = "testdir ";
|
||||||
|
// mkdir(dir_name, disk_name, disk_attr);
|
||||||
|
// char file_name[11] = "data txt";
|
||||||
|
// touch(file_name, disk_name, disk_attr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
BIN
Lab/Lab6/requirements/ZGSOS操作系统实验指导《实验课题20_FAT文件系统模拟设计与实现》.pdf
Normal file
BIN
Lab/Lab6/requirements/ZGSOS操作系统实验指导《实验课题20_FAT文件系统模拟设计与实现》.pdf
Normal file
Binary file not shown.
Binary file not shown.
BIN
Lab/Lab6/requirements/ZGSOS操作系统实验指导《实验课题22_Linux特定文件系统设计探析》.pdf
Normal file
BIN
Lab/Lab6/requirements/ZGSOS操作系统实验指导《实验课题22_Linux特定文件系统设计探析》.pdf
Normal file
Binary file not shown.
492
Lab/Lab6/source/21281280-柯劲帆-第6次实验.md
Normal file
492
Lab/Lab6/source/21281280-柯劲帆-第6次实验.md
Normal file
@ -0,0 +1,492 @@
|
|||||||
|
<h1><center>北京交通大学实验报告</center></h1>
|
||||||
|
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">课程名称</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">操作系统</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">实验题目</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">FAT文件系统模拟与实现</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">学号</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">21281280</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">姓名</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">柯劲帆</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">班级</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">物联网2101班</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">指导老师</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">何永忠</span></div>
|
||||||
|
<div><span style="display: inline-block; width: 65px; text-align: center;">报告日期</span><span style="display: inline-block; width: 25px;">:</span><span style="display: inline-block; width: 310px; font-weight: bold; text-align: left;">2023年12月31日</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 1. 开发运行环境和工具
|
||||||
|
|
||||||
|
| 操作系统 | Linux内核版本 | 处理器 | GCC版本 |
|
||||||
|
| :---------: | :-----------------------: | :--------------------------------------: | :-------------------------------: |
|
||||||
|
| Deepin 20.9 | 5.18.17-amd64-desktop-hwe | Intel(R) Core(TM) i3-2330M CPU @ 2.20GHz | gcc (Uos 8.3.0.3-3+rebuild) 8.3.0 |
|
||||||
|
|
||||||
|
- **其他工具**:
|
||||||
|
- **编辑**:VSCode
|
||||||
|
- **编译和运行**:Terminal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 2. FAT磁盘格式化操作和映像文件生成
|
||||||
|
|
||||||
|
FAT的引导扇区各个字段的定义和说明如下:
|
||||||
|
|
||||||
|
| 字节位移 | 字段长度(字节) | 字段名称 |
|
||||||
|
| -------- | -------------- | ---------------------------- |
|
||||||
|
| 0x00 | 3 | 跳转指令(Jump Instruction) |
|
||||||
|
| 0x03 | 8 | OEM ID |
|
||||||
|
| 0x0B | 25 | BPB |
|
||||||
|
| 0x24 | 26 | 扩展BPB |
|
||||||
|
| 0x3E | 448 | 引导程序代码(Bootstrap Code) |
|
||||||
|
| 0x01FE | 4 | 扇区结束标识符(0xAA55) |
|
||||||
|
|
||||||
|
FAT16分区的BPB字段为:
|
||||||
|
|
||||||
|
| 字节位移 | 字段长度(字节) | 例值 | 名称、定义和描述 |
|
||||||
|
| -------- | -------------- | ----------- | ------------------------------------------------------------ |
|
||||||
|
| 0x0B | 2 | 0x0200 | 扇区字节数(Bytes Per Sector) 硬件扇区的大小。本字段合法的十进制值有512、1024、2048和4096。对大多数磁盘来说,本字段的值为512 |
|
||||||
|
| 0x0D | 1 | 0x10 | 每簇扇区数(Sectors Per Cluster) 一个簇中的扇区数。由于FAT16文件系统只能跟踪有限个簇(最多为65536个)。因此,通过增加每簇的扇区数可以支持最大分区数。分区的缺省的簇的大小取决于该分区的大小。本字段合法的十进制值有 1、2、4、8、16、32、64和128。导致簇大于32KB(每扇区字节数*每簇扇区数)的值会引起磁盘错误和软件错误 |
|
||||||
|
| 0x0e | 2 | 0x0006 | 保留扇区数(Reserved Sector) 第一个FAT开始之前的扇区数,包括引导扇区。 |
|
||||||
|
| 0x10 | 1 | 0x02 | FAT数(Number of FAT)该分区上FAT的副本数。本字段的值一般为2 |
|
||||||
|
| 0x11 | 2 | 0x0200 | 根目录项数(Root Entries) 能够保存在该分区的根目录文件夹中的32个字节长的文件和文件夹名称项的总数。在一个典型的硬盘上,本字段的值为512。其中一个项常常被用作卷标号(Volume Label),长名称的文件和文件夹每个文件使用多个项。文件和文件夹项的最大数一般为511,但是如果使用的长文件名,往往都达不到这个数。 |
|
||||||
|
| 0x13 | 2 | 0x0000 | 小扇区数(Small Sector) 该分区上的扇区数,表示为16位(<65536)。对大于65536个扇区的分区来说,本字段的值为0,而使用大扇区数来取代它。 |
|
||||||
|
| 0x15 | 1 | 0xF8 | 媒体描述符( Media Descriptor)提供有关媒体被使用的信息。值0xF8表示硬盘,0xF0表示高密度的3.5寸软盘。媒体描述符要用于MS-DOS FAT16磁盘,在Windows 2000中未被使用 |
|
||||||
|
| 0x16 | 2 | 0x00F5 | 每FAT扇区数(Sectors Per FAT) 该分区上每个FAT所占用的扇区数。计算机利用这个数和FAT数以及隐藏扇区数来决定根目录在哪里开始。计算机还可以根据根目录中的项数(512)决定该分区的用户数据区从哪里开始 |
|
||||||
|
| 0x18 | 2 | 0x003F | 每道扇区数(Sectors Per Trark) |
|
||||||
|
| 0x1A | 2 | 0x00FF | 磁头数(Number of head) |
|
||||||
|
| 0x1C | 4 | 0x000000400 | 隐藏扇区数(Hidden Sector) 该分区上引导扇区之前的扇区数。在引导序列计算到根目录和数据区的绝对位移的过程中使用了该值 |
|
||||||
|
| 0x20 | 4 | 0x000F4C00 | 大扇区数(Large Sector) 如果小扇区数字段的值为0,本字段就包含该FAT16分区中的总扇区数。如果小扇区数字段的值不为0,那么本字段的值为0 |
|
||||||
|
|
||||||
|
FAT16分区的扩展BPB字段为:
|
||||||
|
|
||||||
|
| 字节位移 | 字段长度(字节) | 图8对应取值 | 名称、定义和描述 |
|
||||||
|
| -------- | -------------- | ----------- | ------------------------------------------------------------ |
|
||||||
|
| 0x24 | 1 | 0x80 | 物理驱动器号( Physical Drive Number) 与BIOS物理驱动器号有关。软盘驱动器被标识为0x00,物理硬盘被标识为0x80,而与物理磁盘驱动器无关。一般地,在发出一个INT13h BIOS调用之前设置该值,具体指定所访问的设备。只有当该设备是一个引导设备时,这个值才有意义 |
|
||||||
|
| 0x25 | 1 | 0x01 | 保留(Reserved) FAT16分区一般将本字段的值设置为1 |
|
||||||
|
| 0x26 | 1 | 0x29 | 扩展引导标签(Extended Boot Signature) 本字段必须要有能被Windows 2000所识别的值0x28或0x29 |
|
||||||
|
| 0x27 | 2 | 0xABA13358 | 卷序号(Volume Serial Number) 在格式化磁盘时所产生的一个随机序号,它有助于区分磁盘 |
|
||||||
|
| 0x2B | 11 | "NO NAME" | 卷标(Volume Label) 本字段只能使用一次,它被用来保存卷标号。现在,卷标被作为一个特殊文件保存在根目录中 |
|
||||||
|
| 0x36 | 8 | "FAT16" | 文件系统类型(File System Type) 根据该磁盘格式,该字段的值可以为FAT、FAT12或FAT16 |
|
||||||
|
|
||||||
|
因此,各参数初始化如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#define BS_jmpBoot_Offset 0x00 // 跳转指令偏移
|
||||||
|
#define BS_jmpBoot_Len 3 // 跳转指令长度
|
||||||
|
#define BS_OEMName_Offset 0x03 // 厂商名称偏移
|
||||||
|
#define BS_OEMName_Len 8 // 厂商名称长度
|
||||||
|
#define BPB_BytsPerSec_Offset 0x0B // 每扇区字节数偏移
|
||||||
|
#define BPB_BytsPerSec_Len 2 // 每扇区字节数长度
|
||||||
|
#define BPB_SecPerClus_Offset 0x0D // 每簇扇区数偏移
|
||||||
|
#define BPB_SecPerClus_Len 1 // 每簇扇区数长度
|
||||||
|
#define BPB_RsvdSecCnt_Offset 0x0E // 保留扇区数 (引导扇区的扇区数)偏移
|
||||||
|
#define BPB_RsvdSecCnt_Len 2 // 保留扇区数 (引导扇区的扇区数)长度
|
||||||
|
#define BPB_NumFATs_Offset 0x10 // FAT的份数偏移
|
||||||
|
#define BPB_NumFATs_Len 1 // FAT的份数长度
|
||||||
|
#define BPB_RootEntCnt_Offset 0x11 // 根目录可容纳的目录项数偏移
|
||||||
|
#define BPB_RootEntCnt_Len 2 // 根目录可容纳的目录项数长度
|
||||||
|
#define BPB_TotSec16_Offset 0x13 // 扇区总数偏移
|
||||||
|
#define BPB_TotSec16_Len 2 // 扇区总数长度
|
||||||
|
#define BPB_Media_Offset 0x15 // 介质描述符偏移
|
||||||
|
#define BPB_Media_Len 1 // 介质描述符长度
|
||||||
|
#define BPB_FATSz16_Offset 0x16 // 每个FAT表扇区数偏移
|
||||||
|
#define BPB_FATSz16_Len 2 // 每个FAT表扇区数长度
|
||||||
|
#define BPB_SecPerTrk_Offset 0x18 // 每磁道扇区数偏移
|
||||||
|
#define BPB_SecPerTrk_Len 2 // 每磁道扇区数长度
|
||||||
|
#define BPB_NumHeads_Offset 0x1A // 磁头数偏移
|
||||||
|
#define BPB_NumHeads_Len 2 // 磁头数长度
|
||||||
|
#define BPB_HiddSec_Offset 0x1C // 隐藏扇区数偏移
|
||||||
|
#define BPB_HiddSec_Len 4 // 隐藏扇区数长度
|
||||||
|
#define BPB_TotSec32_Offset 0x20 // 偏移 如果BPB_TotSec16是0,由这个值记录扇区数
|
||||||
|
#define BPB_TotSec32_Len 4 // 长度 如果BPB_TotSec16是0,由这个值记录扇区数
|
||||||
|
#define BS_DrvNum_Offset 0x24 // int 13h的驱动器号偏移
|
||||||
|
#define BS_DrvNum_Len 1 // int 13h的驱动器号长度
|
||||||
|
#define BS_Reservedl_Offset 0x25 // 偏移 未使用
|
||||||
|
#define BS_Reservedl_Len 1 // 长度 未使用
|
||||||
|
#define BS_BootSig_Offset 0x26 // 扩展引导标记偏移
|
||||||
|
#define BS_BootSig_Len 1 // 扩展引导标记长度
|
||||||
|
#define BS_VolID_Offset 0x27 // 卷序列号偏移
|
||||||
|
#define BS_VolID_Len 4 // 卷序列号长度
|
||||||
|
#define BS_VolLab_Offset 0x2B // 卷标偏移
|
||||||
|
#define BS_VolLab_Len 11 // 卷标长度
|
||||||
|
#define BS_FileSysType_Offset 0x36 // 文件系统类型偏移
|
||||||
|
#define BS_FileSysType_Len 8 // 文件系统类型长度
|
||||||
|
#define DBR_BootCode_Offset 0x3E // 引导代码及其他偏移
|
||||||
|
#define DBR_BootCode_Len 448 // 引导代码及其他长度
|
||||||
|
#define DBR_EndMark_Offset 0x1FE // 结束标志偏移
|
||||||
|
#define DBR_EndMark_Len 2 // 结束标志长度
|
||||||
|
#define DBR_EndMark 0xAA55 // 结束标志
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
short BytsPerSec; // 每扇区字节数
|
||||||
|
char SecPerClus; // 每簇扇区数
|
||||||
|
short RsvdSecCnt; // 保留扇区数 (引导扇区的扇区数)
|
||||||
|
char NumFATs; // FAT的份数
|
||||||
|
short RootEntCnt; // 根目录可容纳的目录项数
|
||||||
|
short TotSec16; // 扇区总数
|
||||||
|
char Media; // 介质描述符
|
||||||
|
short FATSz16; // 每个FAT表扇区数
|
||||||
|
short SecPerTrk; // 每磁道扇区数
|
||||||
|
short NumHeads; // 磁头数
|
||||||
|
int HiddSec; // 隐藏扇区数
|
||||||
|
int TotSec32; // 替代扇区数
|
||||||
|
char DrvNum; // int 13h的驱动器号
|
||||||
|
char Reservedl; // 未使用
|
||||||
|
char BootSig; // 扩展引导标记
|
||||||
|
int VolID; // 卷序列号
|
||||||
|
int TotalSize; // 总磁盘大小
|
||||||
|
int current_dir; // 当前目录的首地址
|
||||||
|
} DISK;
|
||||||
|
|
||||||
|
|
||||||
|
DISK init_disk_attr() {
|
||||||
|
DISK disk;
|
||||||
|
disk.BytsPerSec = 0x0200;
|
||||||
|
disk.SecPerClus = 0x01;
|
||||||
|
disk.RsvdSecCnt = 0x0001;
|
||||||
|
disk.NumFATs = 0x01;
|
||||||
|
disk.RootEntCnt = 0x0200;
|
||||||
|
disk.TotSec16 = 0x2000;
|
||||||
|
disk.Media = 0xf8;
|
||||||
|
disk.FATSz16 = 0x0020;
|
||||||
|
disk.SecPerTrk = 0x0020;
|
||||||
|
disk.NumHeads = 0x0040;
|
||||||
|
disk.HiddSec = 0x00000000;
|
||||||
|
disk.TotSec32 = 0x00000000;
|
||||||
|
disk.DrvNum = 0x80;
|
||||||
|
disk.Reservedl = 0x00;
|
||||||
|
disk.BootSig = 0x29;
|
||||||
|
disk.VolID = 0x00000000;
|
||||||
|
disk.TotalSize = 0x400000;
|
||||||
|
disk.current_dir = 0x4200;
|
||||||
|
return disk;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
初始化和格式化磁盘代码如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void init_file_system(char disk_name[13], DISK disk_attr) {
|
||||||
|
FILE* fp = fopen(disk_name, "wb");
|
||||||
|
// 跳转指令
|
||||||
|
fseek(fp, BS_jmpBoot_Offset, 0);
|
||||||
|
char jmpBoot[BS_jmpBoot_Len] = { 0xEB, 0x3C, 0x90 };
|
||||||
|
fwrite(jmpBoot, 1, BS_jmpBoot_Len, fp);
|
||||||
|
|
||||||
|
// 厂商名称
|
||||||
|
fseek(fp, BS_OEMName_Offset, 0);
|
||||||
|
char OEMName[BS_OEMName_Len] = { 'K', 'e', 'J', 'F', ' ', ' ', ' ', ' ' };
|
||||||
|
fwrite(OEMName, 1, BS_OEMName_Len, fp);
|
||||||
|
|
||||||
|
// 每扇区字节数
|
||||||
|
fseek(fp, BPB_BytsPerSec_Offset, 0);
|
||||||
|
fwrite(&disk_attr.BytsPerSec, BPB_BytsPerSec_Len, 1, fp);
|
||||||
|
|
||||||
|
// 每簇扇区数
|
||||||
|
fseek(fp, BPB_SecPerClus_Offset, 0);
|
||||||
|
fwrite(&disk_attr.SecPerClus, BPB_SecPerClus_Len, 1, fp);
|
||||||
|
|
||||||
|
// 保留扇区数 (引导扇区的扇区数)
|
||||||
|
fseek(fp, BPB_RsvdSecCnt_Offset, 0);
|
||||||
|
fwrite(&disk_attr.RsvdSecCnt, BPB_RsvdSecCnt_Len, 1, fp);
|
||||||
|
|
||||||
|
// FAT的份数
|
||||||
|
fseek(fp, BPB_NumFATs_Offset, 0);
|
||||||
|
fwrite(&disk_attr.NumFATs, BPB_NumFATs_Len, 1, fp);
|
||||||
|
|
||||||
|
// 根目录可容纳的目录项数
|
||||||
|
fseek(fp, BPB_RootEntCnt_Offset, 0);
|
||||||
|
fwrite(&disk_attr.RootEntCnt, BPB_RootEntCnt_Len, 1, fp);
|
||||||
|
|
||||||
|
// 扇区总数
|
||||||
|
fseek(fp, BPB_TotSec16_Offset, 0);
|
||||||
|
fwrite(&disk_attr.TotSec16, BPB_TotSec16_Len, 1, fp);
|
||||||
|
|
||||||
|
// 介质描述符
|
||||||
|
fseek(fp, BPB_Media_Offset, 0);
|
||||||
|
fwrite(&disk_attr.Media, BPB_Media_Len, 1, fp);
|
||||||
|
|
||||||
|
// 每个FAT表扇区数
|
||||||
|
fseek(fp, BPB_FATSz16_Offset, 0);
|
||||||
|
fwrite(&disk_attr.FATSz16, BPB_FATSz16_Len, 1, fp);
|
||||||
|
|
||||||
|
// 每磁道扇区数
|
||||||
|
fseek(fp, BPB_SecPerTrk_Offset, 0);
|
||||||
|
fwrite(&disk_attr.SecPerTrk, BPB_SecPerTrk_Len, 1, fp);
|
||||||
|
|
||||||
|
// 磁头数
|
||||||
|
fseek(fp, BPB_NumHeads_Offset, 0);
|
||||||
|
fwrite(&disk_attr.NumHeads, BPB_NumHeads_Len, 1, fp);
|
||||||
|
|
||||||
|
// 隐藏扇区数
|
||||||
|
fseek(fp, BPB_HiddSec_Offset, 0);
|
||||||
|
fwrite(&disk_attr.HiddSec, BPB_HiddSec_Len, 1, fp);
|
||||||
|
|
||||||
|
// 替代扇区数
|
||||||
|
fseek(fp, BPB_TotSec32_Offset, 0);
|
||||||
|
fwrite(&disk_attr.TotSec32, BPB_TotSec32_Len, 1, fp);
|
||||||
|
|
||||||
|
// int 13h的驱动器号
|
||||||
|
fseek(fp, BS_DrvNum_Offset, 0);
|
||||||
|
fwrite(&disk_attr.DrvNum, BS_DrvNum_Len, 1, fp);
|
||||||
|
|
||||||
|
// 未使用
|
||||||
|
fseek(fp, BS_Reservedl_Offset, 0);
|
||||||
|
fwrite(&disk_attr.Reservedl, BS_Reservedl_Len, 1, fp);
|
||||||
|
|
||||||
|
// 扩展引导标记
|
||||||
|
fseek(fp, BS_BootSig_Offset, 0);
|
||||||
|
fwrite(&disk_attr.BootSig, BS_BootSig_Len, 1, fp);
|
||||||
|
|
||||||
|
// 卷序列号
|
||||||
|
fseek(fp, BS_VolID_Offset, 0);
|
||||||
|
fwrite(&disk_attr.VolID, BS_VolID_Len, 1, fp);
|
||||||
|
|
||||||
|
// 卷标
|
||||||
|
fseek(fp, BS_VolLab_Offset, 0);
|
||||||
|
char VolLab[BS_VolLab_Len] = {'K', 'e', 'J', 'i', 'n', 'g', 'f', 'a', 'n', ' ', ' '};
|
||||||
|
fwrite(VolLab, 1, BS_VolLab_Len, fp);
|
||||||
|
|
||||||
|
// 文件系统类型
|
||||||
|
fseek(fp, BS_FileSysType_Offset, 0);
|
||||||
|
char FileSysType[BS_FileSysType_Len] = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '};
|
||||||
|
fwrite(FileSysType, 1, BS_FileSysType_Len, fp);
|
||||||
|
|
||||||
|
// 引导代码等
|
||||||
|
fseek(fp, DBR_BootCode_Offset, 0);
|
||||||
|
char BootCode[DBR_BootCode_Len] = { 0 };
|
||||||
|
fwrite(BootCode, 1, DBR_BootCode_Len, fp);
|
||||||
|
|
||||||
|
// 结束标志
|
||||||
|
fseek(fp, DBR_EndMark_Offset, 0);
|
||||||
|
short EndMark = DBR_EndMark;
|
||||||
|
fwrite(&EndMark, DBR_EndMark_Len, 1, fp);
|
||||||
|
|
||||||
|
// FAT分区表
|
||||||
|
fseek(fp, 0x0200, 0);
|
||||||
|
int FAT_Len = disk_attr.FATSz16 * disk_attr.BytsPerSec * disk_attr.NumFATs; // 每个FAT表扇区数 * 扇区字节数 * FAT的份数
|
||||||
|
char* FAT_data = (char*)malloc(sizeof(char) * FAT_Len);
|
||||||
|
fwrite(FAT_data, 1, FAT_Len, fp);
|
||||||
|
|
||||||
|
// DATA段
|
||||||
|
fseek(fp, 0x0200 + FAT_Len, 0);
|
||||||
|
int DATA_Len = disk_attr.TotalSize - 0x0200 - FAT_Len;
|
||||||
|
char* DATA_data = (char*)malloc(sizeof(char) * DATA_Len);
|
||||||
|
fwrite(DATA_data, 1, DATA_Len, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
调用这个函数生成.img虚拟磁盘镜像挂载到linux上:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
> gcc ./main.c -o main
|
||||||
|
> ./main
|
||||||
|
> mkdir /media/cdrom
|
||||||
|
> sudo mount -o loop KJF_disk.img /media/cdrom
|
||||||
|
> cd /media/cdrom
|
||||||
|
```
|
||||||
|
|
||||||
|
发现可以正常认盘和使用。
|
||||||
|
|
||||||
|
查看其二进制:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
> hexdump KJF_disk.img -C
|
||||||
|
00000000 eb 3c 90 4b 65 4a 46 20 20 20 20 00 02 01 01 00 |.<.KeJF .....|
|
||||||
|
00000010 01 00 02 00 20 f8 20 00 20 00 40 00 00 00 00 00 |.... . . .@.....|
|
||||||
|
00000020 00 00 00 00 80 00 29 00 00 00 00 4b 65 4a 69 6e |......)....KeJin|
|
||||||
|
00000030 67 66 61 6e 20 20 46 41 54 31 36 20 20 20 00 00 |gfan FAT16 ..|
|
||||||
|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||||
|
*
|
||||||
|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
|
||||||
|
00000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||||
|
*
|
||||||
|
00400000
|
||||||
|
```
|
||||||
|
|
||||||
|
FAT文件格式正确。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 3. 目录
|
||||||
|
|
||||||
|
目录项字段定义:
|
||||||
|
|
||||||
|
| 偏移地址 | 字节数 | 说明 | |
|
||||||
|
| --------- | ------ | ---------------- | ------------------------------------------------------------ |
|
||||||
|
| 0x00~0x07 | 8 | 文件名 | |
|
||||||
|
| 0x08~0x0A | 3 | 扩展名 | |
|
||||||
|
| 0x0B | 1 | 属 性 | 00000000(读写) 00000001(只读) 00000010(隐藏) 00000100(系统) 00001000(卷标)00010000(目录) 00100000(归档) |
|
||||||
|
| 0x0C~0x15 | 10 | 保留 | |
|
||||||
|
| 0x16~0x17 | 2 | 文件最近修改时间 | |
|
||||||
|
| 0x18~0x19 | 2 | 文件最近修改日期 | |
|
||||||
|
| 0x1A~0x1B | 2 | 文件的首簇号 | |
|
||||||
|
| 0x1C~0x1F | 4 | 文件长度大小 | |
|
||||||
|
|
||||||
|
因此代码如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
int mkdir(char dir_name[11], char disk_name[13], DISK disk_attr) {
|
||||||
|
FILE* fp = fopen(disk_name, "rb+");
|
||||||
|
unsigned short dir_firstBlockNum = find_free_blocks(disk_attr, fp);
|
||||||
|
if (dir_firstBlockNum == 0xFFFF) return -1;
|
||||||
|
|
||||||
|
fseek(fp, 0x200 + dir_firstBlockNum * 2, 0);
|
||||||
|
short new_index = 0xFFFF;
|
||||||
|
fwrite(&new_index, 2, 1, fp);
|
||||||
|
|
||||||
|
int start_byte = disk_attr.current_dir;
|
||||||
|
int byte_line_num = 0;
|
||||||
|
while (byte_line_num < disk_attr.BytsPerSec) {
|
||||||
|
fseek(fp, start_byte + byte_line_num, 0);
|
||||||
|
int byte_line[4] = { 0 };
|
||||||
|
fread(byte_line, 4, 3, fp);
|
||||||
|
if (!byte_line[0] && !byte_line[1] && !byte_line[2]) break;
|
||||||
|
byte_line_num += 0x20;
|
||||||
|
}
|
||||||
|
if (byte_line_num >= disk_attr.BytsPerSec) return -1;
|
||||||
|
fseek(fp, start_byte + byte_line_num, 0);
|
||||||
|
fwrite(dir_name, 1, 11, fp);
|
||||||
|
short dir_attr_byte = 0b00010000;
|
||||||
|
fwrite(&dir_attr_byte, 1, 1, fp);
|
||||||
|
|
||||||
|
short dir_reserved_byte[6] = { 0 };
|
||||||
|
fwrite(dir_reserved_byte, 2, 5, fp);
|
||||||
|
|
||||||
|
struct tm time = get_time();
|
||||||
|
short dir_time_byte = time.tm_hour * 2048 + time.tm_min * 32 + time.tm_sec / 2;
|
||||||
|
fwrite(&dir_time_byte, 2, 1, fp);
|
||||||
|
short dir_date_byte = (time.tm_year + 1900 - 1980) * 512 + time.tm_mon * 32 + time.tm_mday;
|
||||||
|
fwrite(&dir_date_byte, 2, 1, fp);
|
||||||
|
fwrite(&dir_firstBlockNum, 2, 1, fp);
|
||||||
|
short dir_size = disk_attr.BytsPerSec * disk_attr.SecPerClus;
|
||||||
|
fwrite(&dir_size, 2, 1, fp);
|
||||||
|
|
||||||
|
int new_block = 0x7800 + disk_attr.BytsPerSec * disk_attr.SecPerClus * dir_firstBlockNum;
|
||||||
|
fseek(fp, new_block, 0);
|
||||||
|
char dot[11] = { '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
|
||||||
|
fwrite(dot, 1, 11, fp);
|
||||||
|
fwrite(&dir_attr_byte, 1, 1, fp);
|
||||||
|
fwrite(dir_reserved_byte, 2, 5, fp);
|
||||||
|
fwrite(&dir_time_byte, 2, 1, fp);
|
||||||
|
fwrite(&dir_date_byte, 2, 1, fp);
|
||||||
|
short dir_oriBlock_byte = 0;
|
||||||
|
fwrite(&dir_oriBlock_byte, 2, 1, fp);
|
||||||
|
unsigned int dir_oriSize = 0;
|
||||||
|
fwrite(&dir_oriSize, 4, 1, fp);
|
||||||
|
|
||||||
|
fseek(fp, new_block + 0x20, 0);
|
||||||
|
char dotdot[11] = { '.', '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
|
||||||
|
fwrite(dotdot, 1, 11, fp);
|
||||||
|
fwrite(&dir_attr_byte, 1, 1, fp);
|
||||||
|
fwrite(dir_reserved_byte, 2, 5, fp);
|
||||||
|
short dir_oriTime_byte = 0;
|
||||||
|
fwrite(&dir_oriTime_byte, 2, 1, fp);
|
||||||
|
short dir_oriDate_byte = (1970 - 1980 + 1900) * 512 + 1 * 32 + 1;
|
||||||
|
fwrite(&dir_oriDate_byte, 2, 1, fp);
|
||||||
|
fwrite(&dir_oriBlock_byte, 2, 1, fp);
|
||||||
|
fwrite(&dir_oriSize, 4, 1, fp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tm get_time() {
|
||||||
|
struct timeval tv;
|
||||||
|
struct timezone tz;
|
||||||
|
struct tm *t;
|
||||||
|
|
||||||
|
gettimeofday(&tv, &tz);
|
||||||
|
t = localtime(&tv.tv_sec);
|
||||||
|
return *t;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 4. 文件
|
||||||
|
|
||||||
|
```c
|
||||||
|
int touch(char file_name[11], char disk_name[13], DISK disk_attr) {
|
||||||
|
FILE* contentFile = fopen("./data.txt", "r");
|
||||||
|
char *content = (char*)malloc(2000 * sizeof(char));
|
||||||
|
fread(content, 1, 2000, contentFile);
|
||||||
|
fclose(contentFile);
|
||||||
|
FILE* fp = fopen(disk_name, "rb+");
|
||||||
|
int file_blockNum = strlen(content) / (disk_attr.BytsPerSec * disk_attr.SecPerClus) + 1;
|
||||||
|
unsigned short* index = (short*)malloc(sizeof(short) * file_blockNum);
|
||||||
|
for (int i = 0; i < file_blockNum; i++) {
|
||||||
|
index[i] = find_free_blocks(disk_attr, fp);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < file_blockNum - 1; i++) {
|
||||||
|
fseek(fp, 0x200 + index[i] * 2, 0);
|
||||||
|
fwrite(&index[i + 1], 2, 1, fp);
|
||||||
|
}
|
||||||
|
fseek(fp, 0x200 + index[file_blockNum - 1] * 2, 0);
|
||||||
|
short last_index = 0xFFFF;
|
||||||
|
fwrite(&last_index, 2, 1, fp);
|
||||||
|
|
||||||
|
int start_byte = disk_attr.current_dir;
|
||||||
|
int byte_line_num = 0;
|
||||||
|
while (byte_line_num < disk_attr.BytsPerSec) {
|
||||||
|
fseek(fp, start_byte + byte_line_num, 0);
|
||||||
|
int byte_line[4] = { 0 };
|
||||||
|
fread(byte_line, 4, 3, fp);
|
||||||
|
if (!byte_line[0] && !byte_line[1] && !byte_line[2]) break;
|
||||||
|
byte_line_num += 0x20;
|
||||||
|
}
|
||||||
|
if (byte_line_num >= disk_attr.BytsPerSec) return -1;
|
||||||
|
fseek(fp, start_byte + byte_line_num, 0);
|
||||||
|
fwrite(file_name, 1, 11, fp);
|
||||||
|
short file_attr_byte = 0b00000000;
|
||||||
|
fwrite(&file_attr_byte, 1, 1, fp);
|
||||||
|
|
||||||
|
short file_reserved_byte[6] = { 0 };
|
||||||
|
fwrite(file_reserved_byte, 2, 5, fp);
|
||||||
|
|
||||||
|
struct tm time = get_time();
|
||||||
|
short file_time_byte = time.tm_hour * 2048 + time.tm_min * 32 + time.tm_sec / 2;
|
||||||
|
fwrite(&file_time_byte, 2, 1, fp);
|
||||||
|
short file_date_byte = (time.tm_year + 1900 - 1980) * 512 + time.tm_mon * 32 + time.tm_mday;
|
||||||
|
fwrite(&file_date_byte, 2, 1, fp);
|
||||||
|
fwrite(&index[0], 2, 1, fp);
|
||||||
|
unsigned int file_size = strlen(content);
|
||||||
|
fwrite(&file_size, 4, 1, fp);
|
||||||
|
|
||||||
|
for (int i = 0; i < file_blockNum; i++) {
|
||||||
|
int new_block = 0x7800 + disk_attr.BytsPerSec * disk_attr.SecPerClus * index[i];
|
||||||
|
fseek(fp, new_block, 0);
|
||||||
|
fwrite(content,
|
||||||
|
file_size > disk_attr.BytsPerSec * disk_attr.SecPerClus ? disk_attr.BytsPerSec * disk_attr.SecPerClus : file_size,
|
||||||
|
1,
|
||||||
|
fp
|
||||||
|
);
|
||||||
|
content += disk_attr.BytsPerSec * disk_attr.SecPerClus;
|
||||||
|
file_size -= disk_attr.BytsPerSec * disk_attr.SecPerClus;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user