《计算机操作系统》 第十一章 -多媒体操作系统

前言

大家好!今天我们深入讲解《计算机操作系统》第十一章 ------ 多媒体操作系统。多媒体操作系统是传统 OS 针对音视频、图像等多媒体数据处理的扩展,核心解决实时性、高带宽、低延迟等问题。本文会结合通俗易懂的概念讲解 + 可直接运行的 C++98 代码 + 架构图 / 流程图,让大家彻底搞懂多媒体 OS 的核心知识点。

注意:所有代码均采用 C++98 标准编写,无任何第三方依赖,可直接编译运行(g++ -std=c++98 文件名.cpp -o 可执行文件)。


11.1 多媒体系统简介

1.1.1 核心概念

多媒体系统是能处理文本、音频、视频、图像 等多种媒体数据,且满足实时性、同步性、连续性要求的计算机系统。比如我们常用的视频播放器、直播软件、音视频服务器,其底层都依赖多媒体 OS 的核心机制。

1.1.2 多媒体系统架构

架构图

1.1.3 核心特征

  1. 实时性:多媒体数据(如视频帧)必须按时处理,否则出现卡顿 / 花屏;
  2. 同步性:音视频需严格同步(比如画面和声音对齐);
  3. 高带宽:视频数据量大,需高 IO 带宽支撑;
  4. 连续性:媒体流不能中断,需持续传输 / 处理。

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 代码说明

  1. 兼容性 :全程遵循 C++98 标准(如不用unordered_mapauto、强类型枚举,字符串转const char*等);

  2. 核心功能:通过文件后缀识别媒体类型,获取文件大小;

  3. 编译运行

    复制代码
    # g++编译命令(指定C++98)
    g++ -std=c++98 media_file_parser.cpp -o media_parser
    # 运行
    ./media_parser
  4. 输出示例

    复制代码
    文件:test.mp3
    类型:音频文件
    大小:文件不存在/无法访问
    -------------------------
    文件:movie.mp4
    类型:视频文件
    大小:文件不存在/无法访问
    -------------------------

11.3 多媒体进程管理中的问题和接纳控制

1.3.1 核心问题

多媒体进程和普通进程的核心差异:

  1. 实时性要求:多媒体进程(如视频解码)必须在规定时间内完成,否则出现卡顿;
  2. 资源需求固定:比如视频播放进程需要固定的 CPU、内存、IO 带宽;
  3. 不可抢占性:部分多媒体进程(如音频播放)不能被抢占,否则出现断音。

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 代码说明

  1. 核心逻辑:模拟 OS 的接纳控制流程,先检查资源再决定是否启动进程;

  2. 编译运行

    复制代码
    g++ -std=c++98 admission_control.cpp -o admission
    ./admission
  3. 输出示例

    复制代码
    ===== 测试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 帧 / 秒)。常见调度算法:

  1. 速率单调调度(RMS):周期越短的进程优先级越高;
  2. 最早截止时间优先(EDF):截止时间越早的进程优先级越高(多媒体 OS 最常用);
  3. 固定优先级调度:给视频 / 音频进程分配固定高优先级。

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 代码说明

  1. 核心逻辑:实现 EDF 调度算法,优先执行截止时间早的任务;

  2. 编译运行

    复制代码
    g++ -std=c++98 edf_scheduler.cpp -o edf_scheduler
    ./edf_scheduler
  3. 输出示例

    复制代码
    ===== 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 媒体服务器核心特征

  1. 并发访问:同时为多个用户提供音视频服务(如视频网站服务器);
  2. 数据量大:单部电影可能达 GB 级,需高效存储;
  3. QoS 保障:保证每个用户的播放流畅(无卡顿);
  4. 带宽敏感:同时服务 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 核心概念

多媒体数据(如视频)需连续 / 半连续存储,否则磁盘寻道时间过长导致卡顿。常见分配方法:

  1. 连续分配:给多媒体文件分配连续的磁盘块(优点:访问快;缺点:易产生碎片);
  2. 链式分配:用链表连接磁盘块(优点:无碎片;缺点:寻道时间长);
  3. 索引分配:为文件建立索引表,记录所有磁盘块(平衡连续 / 链式的优缺点,多媒体 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 核心概念

  1. 高速缓存(Cache):将常用的多媒体数据(如最近播放的视频帧)缓存到内存,减少磁盘 IO;
  2. 磁盘调度 :优化磁盘寻道顺序,减少多媒体数据的读取延迟。常见算法:
    • 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 代码说明

  1. 核心逻辑:实现 SSTF 磁盘调度(减少寻道时间)+ LRU 缓存(提升访问速度);

  2. 编译运行

    复制代码
    g++ -std=c++98 cache_disk_scheduler.cpp -o cache_scheduler
    ./cache_scheduler

总结

核心知识点回顾

  1. 多媒体 OS 核心需求:实时性、同步性、高带宽、连续性,是区别于传统 OS 的关键;
  2. 核心机制
    • 接纳控制:启动前检查资源,避免系统过载;
    • 实时调度:EDF 算法优先保证截止时间早的多媒体任务;
    • 存储管理:索引分配平衡连续 / 链式的优缺点,SSTF 调度减少磁盘寻道时间;
  3. 性能优化:高速缓存(LRU)提升多媒体数据访问速度,是媒体服务器的核心优化手段。
相关推荐
chinesegf2 小时前
嵌入模型和大语言模型的关系
人工智能·语言模型·自然语言处理
独自破碎E2 小时前
【滑动窗口】最长无重复子数组
java·开发语言
木井巳2 小时前
【Java】数据类型及运算符重点总结
java·开发语言
码农水水2 小时前
美团Java面试被问:Netty的ByteBuf引用计数和内存释放
java·开发语言·数据库·mysql·算法·面试·职场和发展
a努力。2 小时前
国家电网Java面试被问:分布式Top K问题的解决方案
java·开发语言·分布式·oracle·面试·职场和发展·kafka
码农水水2 小时前
浅谈 MySQL InnoDB 的内存组件
java·开发语言·数据库·后端·mysql·面试
_ziva_2 小时前
分布式(三)深入浅出理解PyTorch分布式训练:nn.parallel.DistributedDataParallel详解
人工智能·pytorch·分布式
shjita2 小时前
mapreduce输出乱码的处理
java·开发语言·数据库
江南小书生2 小时前
非标制造行业装配报工工时不准?缺料干扰+标准缺失如何破局?
大数据·人工智能