前言
大家好!今天我们深入讲解《计算机操作系统》第十一章 ------ 多媒体操作系统。多媒体操作系统是传统 OS 针对音视频、图像等多媒体数据处理的扩展,核心解决实时性、高带宽、低延迟等问题。本文会结合通俗易懂的概念讲解 + 可直接运行的 C++98 代码 + 架构图 / 流程图,让大家彻底搞懂多媒体 OS 的核心知识点。
注意:所有代码均采用 C++98 标准编写,无任何第三方依赖,可直接编译运行(g++ -std=c++98 文件名.cpp -o 可执行文件)。
11.1 多媒体系统简介
1.1.1 核心概念
多媒体系统是能处理文本、音频、视频、图像 等多种媒体数据,且满足实时性、同步性、连续性要求的计算机系统。比如我们常用的视频播放器、直播软件、音视频服务器,其底层都依赖多媒体 OS 的核心机制。
1.1.2 多媒体系统架构
架构图
1.1.3 核心特征
- 实时性:多媒体数据(如视频帧)必须按时处理,否则出现卡顿 / 花屏;
- 同步性:音视频需严格同步(比如画面和声音对齐);
- 高带宽:视频数据量大,需高 IO 带宽支撑;
- 连续性:媒体流不能中断,需持续传输 / 处理。
11.2 多媒体文件中的各种媒体
1.2.1 核心概念
多媒体文件是多种媒体数据的封装体,常见媒体类型包括:
- 音频:MP3、WAV、AAC(连续流式数据,对延迟敏感);
- 视频:H.264、MP4、AVI(由帧序列组成,需按帧率播放);
- 图像:JPG、PNG(静态数据,需高分辨率存储);
- 文本:字幕、说明(需与音视频同步显示)。
1.2.2 实战案例:多媒体文件解析(C++98 代码)
以下代码实现多媒体文件的媒体类型识别,兼容 C++98 标准,无第三方依赖:
#include <iostream>
#include <fstream>
#include <string>
#include <cstring> // C++98需用cstring而非string.h
using namespace std;
// 多媒体类型枚举(C++98不支持强类型枚举,用普通枚举)
enum MediaType {
MEDIA_UNKNOWN, // 未知类型
MEDIA_AUDIO, // 音频
MEDIA_VIDEO, // 视频
MEDIA_IMAGE, // 图像
MEDIA_TEXT // 文本
};
// 多媒体文件解析类(C++98风格)
class MediaFileParser {
private:
string filename; // 文件名
MediaType mediaType; // 媒体类型
// 后缀名映射表(C++98不支持unordered_map,用数组+字符串比较)
struct SuffixMap {
const char* suffix;
MediaType type;
} suffixMap[8] = {
{".mp3", MEDIA_AUDIO},
{".wav", MEDIA_AUDIO},
{".mp4", MEDIA_VIDEO},
{".avi", MEDIA_VIDEO},
{".jpg", MEDIA_IMAGE},
{".png", MEDIA_IMAGE},
{".txt", MEDIA_TEXT},
{".srt", MEDIA_TEXT}
};
// 提取文件后缀名
string getSuffix() const {
size_t dotPos = filename.find_last_of('.');
if (dotPos == string::npos) return "";
return filename.substr(dotPos);
}
public:
// 构造函数(C++98无列表初始化简化写法)
MediaFileParser(const string& fname) {
filename = fname;
mediaType = MEDIA_UNKNOWN;
}
// 解析文件类型
void parse() {
string suffix = getSuffix();
// C++98遍历数组
for (int i = 0; i < 8; ++i) {
if (suffix == suffixMap[i].suffix) {
mediaType = suffixMap[i].type;
break;
}
}
}
// 获取媒体类型描述
string getMediaTypeDesc() const {
switch (mediaType) {
case MEDIA_AUDIO: return "音频文件";
case MEDIA_VIDEO: return "视频文件";
case MEDIA_IMAGE: return "图像文件";
case MEDIA_TEXT: return "文本文件";
default: return "未知文件类型";
}
}
// 获取文件大小(字节)
long getFileSize() const {
ifstream file(filename.c_str(), ios::binary | ios::ate); // C++98需转const char*
if (!file.is_open()) {
return -1;
}
long size = file.tellg();
file.close();
return size;
}
};
// 主函数(测试)
int main() {
// 测试用例:可替换为自己的文件路径
string testFiles[] = {"test.mp3", "movie.mp4", "photo.jpg", "subtitle.srt", "data.bin"};
int fileCount = sizeof(testFiles) / sizeof(testFiles[0]);
// C++98遍历数组
for (int i = 0; i < fileCount; ++i) {
MediaFileParser parser(testFiles[i]);
parser.parse();
long size = parser.getFileSize();
cout << "文件:" << testFiles[i] << endl;
cout << "类型:" << parser.getMediaTypeDesc() << endl;
if (size >= 0) {
cout << "大小:" << size << " 字节" << endl;
} else {
cout << "大小:文件不存在/无法访问" << endl;
}
cout << "-------------------------" << endl;
}
return 0;
}
1.2.3 代码说明
-
兼容性 :全程遵循 C++98 标准(如不用
unordered_map、auto、强类型枚举,字符串转const char*等); -
核心功能:通过文件后缀识别媒体类型,获取文件大小;
-
编译运行 :
# g++编译命令(指定C++98) g++ -std=c++98 media_file_parser.cpp -o media_parser # 运行 ./media_parser -
输出示例 :
文件:test.mp3 类型:音频文件 大小:文件不存在/无法访问 ------------------------- 文件:movie.mp4 类型:视频文件 大小:文件不存在/无法访问 -------------------------
11.3 多媒体进程管理中的问题和接纳控制
1.3.1 核心问题
多媒体进程和普通进程的核心差异:
- 实时性要求:多媒体进程(如视频解码)必须在规定时间内完成,否则出现卡顿;
- 资源需求固定:比如视频播放进程需要固定的 CPU、内存、IO 带宽;
- 不可抢占性:部分多媒体进程(如音频播放)不能被抢占,否则出现断音。
1.3.2 接纳控制(Admission Control)
接纳控制是多媒体 OS 的核心机制:在启动新的多媒体进程前,OS 会检查系统剩余资源(CPU、内存、带宽)是否满足进程的最低需求,只有满足才接纳,否则拒绝(避免系统过载)。
1.3.3 实战案例:多媒体进程接纳控制(C++98 代码)
#include <iostream>
#include <string>
#include <vector> // C++98支持vector
using namespace std;
// 系统资源结构体(C++98风格)
struct SystemResources {
int cpuUsage; // CPU使用率(0-100)
int memoryFree; // 空闲内存(MB)
int bandwidth; // 可用带宽(MB/s)
// 构造函数
SystemResources(int cpu, int mem, int bw) {
cpuUsage = cpu;
memoryFree = mem;
bandwidth = bw;
}
};
// 多媒体进程结构体
struct MediaProcess {
string name; // 进程名
int cpuMin; // 最小CPU需求(%)
int memoryMin; // 最小内存需求(MB)
int bandwidthMin; // 最小带宽需求(MB/s)
// 构造函数
MediaProcess(const string& n, int cpu, int mem, int bw) {
name = n;
cpuMin = cpu;
memoryMin = mem;
bandwidthMin = bw;
}
};
// 接纳控制器类
class AdmissionController {
private:
SystemResources sysRes; // 系统当前资源
// 检查资源是否满足
bool checkResources(const MediaProcess& proc) const {
// 剩余CPU = 100 - 当前使用率
int cpuAvailable = 100 - sysRes.cpuUsage;
return (cpuAvailable >= proc.cpuMin) &&
(sysRes.memoryFree >= proc.memoryMin) &&
(sysRes.bandwidth >= proc.bandwidthMin);
}
public:
// 构造函数
AdmissionController(const SystemResources& res) : sysRes(res) {}
// 接纳控制决策
bool admitProcess(const MediaProcess& proc) {
cout << "正在检查进程[" << proc.name << "]的资源需求..." << endl;
cout << "进程需求:CPU=" << proc.cpuMin << "% 内存=" << proc.memoryMin << "MB 带宽=" << proc.bandwidthMin << "MB/s" << endl;
cout << "系统剩余:CPU=" << (100 - sysRes.cpuUsage) << "% 内存=" << sysRes.memoryFree << "MB 带宽=" << sysRes.bandwidth << "MB/s" << endl;
if (checkResources(proc)) {
cout << "✅ 资源满足,接纳该多媒体进程!" << endl;
// 占用资源(模拟)
sysRes.cpuUsage += proc.cpuMin;
sysRes.memoryFree -= proc.memoryMin;
sysRes.bandwidth -= proc.bandwidthMin;
return true;
} else {
cout << "❌ 资源不足,拒绝接纳该多媒体进程!" << endl;
return false;
}
}
};
// 主函数
int main() {
// 初始化系统资源:CPU使用率60% 空闲内存512MB 可用带宽20MB/s
SystemResources sysRes(60, 512, 20);
AdmissionController controller(sysRes);
// 定义多媒体进程
MediaProcess videoPlayer("视频播放器", 20, 128, 10); // 需20%CPU、128MB内存、10MB/s带宽
MediaProcess audioPlayer("音频播放器", 5, 32, 2); // 需5%CPU、32MB内存、2MB/s带宽
MediaProcess liveStream("直播推流", 30, 256, 15); // 需30%CPU、256MB内存、15MB/s带宽
// 测试接纳控制
cout << "===== 测试1:启动视频播放器 =====" << endl;
controller.admitProcess(videoPlayer);
cout << "\n===== 测试2:启动音频播放器 =====" << endl;
controller.admitProcess(audioPlayer);
cout << "\n===== 测试3:启动直播推流 =====" << endl;
controller.admitProcess(liveStream);
return 0;
}
1.3.4 代码说明
-
核心逻辑:模拟 OS 的接纳控制流程,先检查资源再决定是否启动进程;
-
编译运行 :
g++ -std=c++98 admission_control.cpp -o admission ./admission -
输出示例 :
===== 测试1:启动视频播放器 ===== 正在检查进程[视频播放器]的资源需求... 进程需求:CPU=20% 内存=128MB 带宽=10MB/s 系统剩余:CPU=40% 内存=512MB 带宽=20MB/s ✅ 资源满足,接纳该多媒体进程! ===== 测试2:启动音频播放器 ===== 正在检查进程[音频播放器]的资源需求... 进程需求:CPU=5% 内存=32MB 带宽=2MB/s 系统剩余:CPU=20% 内存=384MB 带宽=10MB/s ✅ 资源满足,接纳该多媒体进程! ===== 测试3:启动直播推流 ===== 正在检查进程[直播推流]的资源需求... 进程需求:CPU=30% 内存=256MB 带宽=15MB/s 系统剩余:CPU=15% 内存=352MB 带宽=8MB/s ❌ 资源不足,拒绝接纳该多媒体进程!
1.3.5 接纳控制流程图

11.4 多媒体实时调度
1.4.1 核心概念
多媒体实时调度的目标是保证多媒体进程按时完成任务(如每 33ms 处理一帧视频,对应 30 帧 / 秒)。常见调度算法:
- 速率单调调度(RMS):周期越短的进程优先级越高;
- 最早截止时间优先(EDF):截止时间越早的进程优先级越高(多媒体 OS 最常用);
- 固定优先级调度:给视频 / 音频进程分配固定高优先级。
1.4.2 实战案例:EDF 实时调度(C++98 代码)
#include <iostream>
#include <vector>
#include <algorithm> // C++98支持sort
#include <string>
using namespace std;
// 多媒体任务结构体
struct MediaTask {
string name; // 任务名
int releaseTime; // 释放时间(ms)
int deadline; // 截止时间(ms)
int executionTime; // 执行时间(ms)
bool isCompleted; // 是否完成
// 构造函数
MediaTask(const string& n, int rt, int dl, int et) {
name = n;
releaseTime = rt;
deadline = dl;
executionTime = et;
isCompleted = false;
}
};
// EDF调度比较函数(按截止时间升序)
bool compareDeadline(const MediaTask& t1, const MediaTask& t2) {
return t1.deadline < t2.deadline;
}
// EDF调度器类
class EDFScheduler {
private:
vector<MediaTask> tasks; // 任务列表
int currentTime; // 当前时间(ms)
public:
// 构造函数
EDFScheduler() {
currentTime = 0;
}
// 添加任务
void addTask(const MediaTask& task) {
tasks.push_back(task);
}
// 执行调度
void schedule() {
cout << "===== EDF实时调度开始 =====" << endl;
cout << "当前时间\t执行任务\t剩余执行时间\t截止时间" << endl;
// 只要有未完成的任务就继续调度
while (true) {
// 筛选当前可执行的任务(已释放且未完成)
vector<MediaTask*> availableTasks;
for (size_t i = 0; i < tasks.size(); ++i) {
if (!tasks[i].isCompleted && tasks[i].releaseTime <= currentTime) {
availableTasks.push_back(&tasks[i]);
}
}
if (availableTasks.empty()) {
// 无可用任务,时间推进
currentTime++;
// 检查是否所有任务都完成
bool allCompleted = true;
for (size_t i = 0; i < tasks.size(); ++i) {
if (!tasks[i].isCompleted) {
allCompleted = false;
break;
}
}
if (allCompleted) break;
continue;
}
// 按截止时间排序(EDF核心)
sort(availableTasks.begin(), availableTasks.end(),
[](const MediaTask* t1, const MediaTask* t2) {
return t1->deadline < t2->deadline;
});
// 执行优先级最高的任务
MediaTask* currentTask = availableTasks[0];
cout << currentTime << "ms\t\t" << currentTask->name << "\t\t"
<< currentTask->executionTime << "ms\t\t" << currentTask->deadline << "ms" << endl;
// 执行1ms
currentTask->executionTime--;
currentTime++;
// 检查是否完成
if (currentTask->executionTime == 0) {
currentTask->isCompleted = true;
cout << "✅ 任务[" << currentTask->name << "]完成(完成时间:" << currentTime << "ms,截止时间:" << currentTask->deadline << "ms)" << endl;
}
// 检查是否超时
if (currentTime > currentTask->deadline && !currentTask->isCompleted) {
cout << "❌ 任务[" << currentTask->name << "]超时(当前时间:" << currentTime << "ms,截止时间:" << currentTask->deadline << "ms)" << endl;
}
}
cout << "===== EDF实时调度结束 =====" << endl;
}
};
// 主函数
int main() {
EDFScheduler scheduler;
// 添加多媒体任务(模拟30帧/秒视频:每帧截止时间33ms)
scheduler.addTask(MediaTask("视频帧1", 0, 33, 10)); // 0ms释放,33ms截止,执行10ms
scheduler.addTask(MediaTask("视频帧2", 33, 66, 10)); // 33ms释放,66ms截止,执行10ms
scheduler.addTask(MediaTask("音频采样", 0, 10, 2)); // 0ms释放,10ms截止,执行2ms
// 执行调度
scheduler.schedule();
return 0;
}
1.4.3 代码说明
-
核心逻辑:实现 EDF 调度算法,优先执行截止时间早的任务;
-
编译运行 :
g++ -std=c++98 edf_scheduler.cpp -o edf_scheduler ./edf_scheduler -
输出示例 :
===== EDF实时调度开始 ===== 当前时间 执行任务 剩余执行时间 截止时间 0ms 音频采样 2ms 10ms 1ms 音频采样 1ms 10ms ✅ 任务[音频采样]完成(完成时间:2ms,截止时间:10ms) 2ms 视频帧1 10ms 33ms 3ms 视频帧1 9ms 33ms ... 12ms 视频帧1 0ms 33ms ✅ 任务[视频帧1]完成(完成时间:12ms,截止时间:33ms) ... ===== EDF实时调度结束 =====
11.5 媒体服务器的特征和接纳控制
1.5.1 媒体服务器核心特征
- 并发访问:同时为多个用户提供音视频服务(如视频网站服务器);
- 数据量大:单部电影可能达 GB 级,需高效存储;
- QoS 保障:保证每个用户的播放流畅(无卡顿);
- 带宽敏感:同时服务 1000 个用户,需 1000*10MB/s=10GB/s 带宽。
1.5.2 媒体服务器接纳控制
媒体服务器的接纳控制需考虑:
- 总带宽上限(如服务器出口带宽 10GB/s);
- 单用户带宽需求(如高清视频 10MB/s);
- 最大并发用户数 = 总带宽 / 单用户带宽。
1.5.3 实战案例:媒体服务器接纳控制(C++98 代码)
cpp
#include <iostream>
#include <string>
#include <vector>
// 引入C++98的字符串转换头文件
#include <sstream>
using namespace std;
// 【C++98兼容】将整数转换为字符串(替代to_string)
string intToString(int num) {
ostringstream oss;
oss << num;
return oss.str();
}
// 用户结构体
struct User {
string userId; // 用户ID
int bandwidthNeed; // 单用户带宽需求(MB/s)
bool isServed; // 是否正在服务
// 构造函数(C++98风格)
User(const string& id, int bw) {
userId = id;
bandwidthNeed = bw;
isServed = false;
}
};
// 媒体服务器类
class MediaServer {
private:
int totalBandwidth; // 总带宽(MB/s)
int usedBandwidth; // 已用带宽(MB/s)
vector<User> users; // 用户列表
int maxUsers; // 最大并发用户数
public:
// 构造函数
MediaServer(int totalBW, int perUserBW) {
totalBandwidth = totalBW;
usedBandwidth = 0;
maxUsers = totalBW / perUserBW;
}
// 接纳用户请求
bool admitUser(const string& userId, int perUserBW) {
// 检查最大用户数
int currentUserCount = 0;
for (size_t i = 0; i < users.size(); ++i) {
if (users[i].isServed) currentUserCount++;
}
cout << "当前并发用户数:" << currentUserCount << ",最大支持:" << maxUsers << endl;
cout << "当前已用带宽:" << usedBandwidth << "MB/s,总带宽:" << totalBandwidth << "MB/s" << endl;
if (currentUserCount >= maxUsers) {
cout << "? 拒绝用户[" << userId << "]:并发用户数已达上限!" << endl;
return false;
}
// 检查带宽
if (usedBandwidth + perUserBW > totalBandwidth) {
cout << "? 拒绝用户[" << userId << "]:带宽不足!" << endl;
return false;
}
// 接纳用户
users.push_back(User(userId, perUserBW));
users.back().isServed = true;
usedBandwidth += perUserBW;
cout << "? 接纳用户[" << userId << "]:分配带宽" << perUserBW << "MB/s" << endl;
return true;
}
// 用户退出
void userQuit(const string& userId) {
for (size_t i = 0; i < users.size(); ++i) {
if (users[i].userId == userId && users[i].isServed) {
usedBandwidth -= users[i].bandwidthNeed;
users[i].isServed = false;
cout << "?? 用户[" << userId << "]退出,释放带宽" << users[i].bandwidthNeed << "MB/s" << endl;
return;
}
}
cout << "? 用户[" << userId << "]不存在或未在服务!" << endl;
}
// 打印服务器状态
void printStatus() {
cout << "\n===== 媒体服务器状态 =====" << endl;
cout << "总带宽:" << totalBandwidth << "MB/s" << endl;
cout << "已用带宽:" << usedBandwidth << "MB/s" << endl;
cout << "剩余带宽:" << (totalBandwidth - usedBandwidth) << "MB/s" << endl;
int activeUsers = 0;
for (size_t i = 0; i < users.size(); ++i) {
if (users[i].isServed) activeUsers++;
}
cout << "当前并发用户数:" << activeUsers << "/" << maxUsers << endl;
}
};
// 主函数
int main() {
// 初始化媒体服务器:总带宽100MB/s,单用户高清视频10MB/s → 最大10个并发用户
MediaServer server(100, 10);
// 模拟用户请求
server.admitUser("user001", 10);
server.admitUser("user002", 10);
server.admitUser("user003", 10);
server.printStatus();
// 模拟10个用户(达上限)
// 【关键修复】使用C++98的intToString函数替代to_string
for (int i = 4; i <= 10; ++i) {
string userId = "user00" + intToString(i);
server.admitUser(userId, 10);
}
// 第11个用户(拒绝)
server.admitUser("user011", 10);
// 模拟用户退出
server.userQuit("user005");
server.printStatus();
// 再次接纳用户
server.admitUser("user011", 10);
server.printStatus();
return 0;
}
11.6 多媒体存储器的分配方法
1.6.1 核心概念
多媒体数据(如视频)需连续 / 半连续存储,否则磁盘寻道时间过长导致卡顿。常见分配方法:
- 连续分配:给多媒体文件分配连续的磁盘块(优点:访问快;缺点:易产生碎片);
- 链式分配:用链表连接磁盘块(优点:无碎片;缺点:寻道时间长);
- 索引分配:为文件建立索引表,记录所有磁盘块(平衡连续 / 链式的优缺点,多媒体 OS 常用)。
1.6.2 实战案例:索引分配实现(C++98 代码)
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 磁盘块结构体
struct DiskBlock {
int blockId; // 块ID
bool isAllocated; // 是否已分配
string data; // 块数据(模拟)
DiskBlock(int id) {
blockId = id;
isAllocated = false;
data = "";
}
};
// 索引分配管理器
class IndexAllocator {
private:
vector<DiskBlock> disk; // 模拟磁盘(100个块)
vector<int> indexTable; // 索引表(记录文件占用的块ID)
string fileName; // 文件名
int blockSize; // 块大小(字节)
public:
// 构造函数
IndexAllocator(const string& fname, int bSize) {
fileName = fname;
blockSize = bSize;
// 初始化磁盘(100个块)
for (int i = 0; i < 100; ++i) {
disk.push_back(DiskBlock(i));
}
}
// 分配磁盘块
bool allocateBlocks(int numBlocks) {
cout << "为文件[" << fileName << "]分配" << numBlocks << "个磁盘块..." << endl;
int allocated = 0;
// 寻找空闲块
for (size_t i = 0; i < disk.size() && allocated < numBlocks; ++i) {
if (!disk[i].isAllocated) {
disk[i].isAllocated = true;
indexTable.push_back(disk[i].blockId);
allocated++;
cout << "分配块ID:" << disk[i].blockId << endl;
}
}
if (allocated == numBlocks) {
cout << "✅ 成功分配" << numBlocks << "个块!" << endl;
return true;
} else {
cout << "❌ 仅分配" << allocated << "个块,磁盘空间不足!" << endl;
// 回滚已分配的块
for (int i = 0; i < allocated; ++i) {
disk[indexTable.back()].isAllocated = false;
indexTable.pop_back();
}
return false;
}
}
// 释放磁盘块
void freeBlocks() {
cout << "释放文件[" << fileName << "]的磁盘块..." << endl;
for (size_t i = 0; i < indexTable.size(); ++i) {
int blockId = indexTable[i];
disk[blockId].isAllocated = false;
disk[blockId].data = "";
cout << "释放块ID:" << blockId << endl;
}
indexTable.clear();
cout << "✅ 所有块已释放!" << endl;
}
// 读取文件(模拟)
void readFile() {
cout << "读取文件[" << fileName << "]:" << endl;
for (size_t i = 0; i < indexTable.size(); ++i) {
int blockId = indexTable[i];
cout << "读取块" << blockId << ":" << disk[blockId].data << endl;
}
}
// 写入数据(模拟)
void writeData(const string& data) {
cout << "向文件[" << fileName << "]写入数据..." << endl;
// 计算需要的块数
int numBlocks = (data.size() + blockSize - 1) / blockSize; // 向上取整
if (indexTable.empty()) {
if (!allocateBlocks(numBlocks)) return;
}
// 写入数据到块
int dataPos = 0;
for (size_t i = 0; i < indexTable.size() && dataPos < data.size(); ++i) {
int blockId = indexTable[i];
int writeSize = min(blockSize, (int)(data.size() - dataPos));
disk[blockId].data = data.substr(dataPos, writeSize);
dataPos += writeSize;
cout << "写入块" << blockId << ":" << disk[blockId].data << endl;
}
}
// 打印索引表
void printIndexTable() {
cout << "文件[" << fileName << "]的索引表:";
for (size_t i = 0; i < indexTable.size(); ++i) {
cout << indexTable[i] << " ";
}
cout << endl;
}
};
// 主函数
int main() {
// 初始化索引分配器:文件名为video.mp4,块大小10字节
IndexAllocator allocator("video.mp4", 10);
// 写入模拟视频数据(35字节 → 需要4个块)
string videoData = "VIDEO_FRAME_001_VIDEO_FRAME_002_VIDEO_FRAME_003";
allocator.writeData(videoData);
// 打印索引表
allocator.printIndexTable();
// 读取文件
allocator.readFile();
// 释放块
allocator.freeBlocks();
return 0;
}
11.7 高速缓存与磁盘调度
1.7.1 核心概念
- 高速缓存(Cache):将常用的多媒体数据(如最近播放的视频帧)缓存到内存,减少磁盘 IO;
- 磁盘调度 :优化磁盘寻道顺序,减少多媒体数据的读取延迟。常见算法:
- FCFS:先到先服务(简单但效率低);
- SSTF:最短寻道时间优先(优先访问离当前磁头最近的块);
- SCAN:电梯算法(磁头单向移动,到达端点后反向)。
1.7.2 实战案例:SSTF 磁盘调度(C++98 代码)
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <string>
using namespace std;
// SSTF磁盘调度器
class SSTFScheduler {
private:
vector<int> requestQueue; // 请求队列(磁道号)
int currentHead; // 当前磁头位置
int totalSeekTime; // 总寻道时间(每移动1磁道=1ms)
// 找到离当前磁头最近的请求
int findClosestRequest() {
int minDistance = 999999;
int closestIndex = -1;
for (size_t i = 0; i < requestQueue.size(); ++i) {
int distance = abs(requestQueue[i] - currentHead);
if (distance < minDistance) {
minDistance = distance;
closestIndex = i;
}
}
return closestIndex;
}
public:
// 构造函数
SSTFScheduler(int startHead) {
currentHead = startHead;
totalSeekTime = 0;
}
// 添加请求
void addRequest(int track) {
requestQueue.push_back(track);
}
// 执行调度
void schedule() {
cout << "===== SSTF磁盘调度开始 =====" << endl;
cout << "初始磁头位置:" << currentHead << endl;
cout << "请求队列:";
for (size_t i = 0; i < requestQueue.size(); ++i) {
cout << requestQueue[i] << " ";
}
cout << endl;
while (!requestQueue.empty()) {
// 找到最近的请求
int closestIdx = findClosestRequest();
if (closestIdx == -1) break;
int targetTrack = requestQueue[closestIdx];
int distance = abs(targetTrack - currentHead);
totalSeekTime += distance;
// 输出调度过程
cout << "磁头从" << currentHead << "移动到" << targetTrack
<< ",距离:" << distance << "ms" << endl;
// 更新磁头位置
currentHead = targetTrack;
// 移除已处理的请求
requestQueue.erase(requestQueue.begin() + closestIdx);
}
cout << "===== SSTF磁盘调度结束 =====" << endl;
cout << "总寻道时间:" << totalSeekTime << "ms" << endl;
}
};
// 高速缓存类(LRU替换)
class MediaCache {
private:
vector<string> cache; // 缓存列表
int maxSize; // 缓存最大容量
// 查找缓存项
int findCacheItem(const string& dataId) {
for (size_t i = 0; i < cache.size(); ++i) {
if (cache[i] == dataId) {
return i;
}
}
return -1;
}
public:
// 构造函数
MediaCache(int size) {
maxSize = size;
}
// 访问缓存
bool accessCache(const string& dataId) {
int idx = findCacheItem(dataId);
if (idx != -1) {
// 命中:移到队首(LRU)
cache.erase(cache.begin() + idx);
cache.insert(cache.begin(), dataId);
cout << "✅ 缓存命中:" << dataId << endl;
return true;
} else {
// 未命中:添加到缓存
cout << "❌ 缓存未命中:" << dataId << endl;
if (cache.size() >= maxSize) {
// 容量满,移除最后一项(最久未使用)
cout << "缓存满,移除最久未使用项:" << cache.back() << endl;
cache.pop_back();
}
cache.insert(cache.begin(), dataId);
return false;
}
}
// 打印缓存状态
void printCache() {
cout << "当前缓存:";
for (size_t i = 0; i < cache.size(); ++i) {
cout << cache[i] << " ";
}
cout << endl;
}
};
// 主函数
int main() {
// 1. 测试SSTF磁盘调度
SSTFScheduler diskScheduler(50);
// 模拟视频数据的磁道请求
diskScheduler.addRequest(10);
diskScheduler.addRequest(90);
diskScheduler.addRequest(30);
diskScheduler.addRequest(70);
diskScheduler.schedule();
// 2. 测试多媒体缓存
cout << "\n===== 多媒体缓存测试 =====" << endl;
MediaCache cache(3); // 缓存容量3
cache.accessCache("video_frame_001");
cache.accessCache("video_frame_002");
cache.accessCache("video_frame_003");
cache.printCache();
cache.accessCache("video_frame_001"); // 命中
cache.accessCache("video_frame_004"); // 未命中,移除最久未使用
cache.printCache();
return 0;
}
1.7.3 代码说明
-
核心逻辑:实现 SSTF 磁盘调度(减少寻道时间)+ LRU 缓存(提升访问速度);
-
编译运行 :
g++ -std=c++98 cache_disk_scheduler.cpp -o cache_scheduler ./cache_scheduler
总结
核心知识点回顾
- 多媒体 OS 核心需求:实时性、同步性、高带宽、连续性,是区别于传统 OS 的关键;
- 核心机制 :
- 接纳控制:启动前检查资源,避免系统过载;
- 实时调度:EDF 算法优先保证截止时间早的多媒体任务;
- 存储管理:索引分配平衡连续 / 链式的优缺点,SSTF 调度减少磁盘寻道时间;
- 性能优化:高速缓存(LRU)提升多媒体数据访问速度,是媒体服务器的核心优化手段。








