深大操作系统实验-简易文件系统设计

目录

问题描述

设计思路

文件逻辑设计

用到的常量及数据结构

一些基础功能接口(从小到大)

对位图进行操作(位运算)

对数据块进行操作(释放,申请,调用上面的位图控制函数实现)

文件创建与删除

文件的读取和修改

文件夹的创建和删除

cd和ls指令

其他辅助功能函数

进程同步

总结


问题描述

1.创建一个100M的文件或者创建一个100M的共享内存
2.尝试自行设计一个C语言小程序,使用步骤1分配的100M空间(共享内存或mmap),然后假设这100M空间为一个空白磁盘,设计一个简单的文件系统管理这个空白磁盘,给出文件和目录管理的基本数据结构,并画出文件系统基本结构图,以及基本操作接口。
3.在步骤1的基础上实现部分文件操作接口操作,创建目录mkdir,删除目录rmdir,修改名称,创建文件open,修改文件,删除文件rm,查看文件系统目录结构ls
4.参考进程同步的相关章节,通过信号量机制实现多个终端对上述文件系统的互斥访问,系统中的一个文件允许多个进程读,不允许写操作;或者只允许一个写操作,不允许读。

设计思路

模拟FAT文件系统(软硬链接没做出来,数据结构也不支持,寄)

首先100MB中拿出4MB作为文件管理系统的核心(存放位图,inode数组等等),100MB大小空间安排如下:

对于后面的96MB,以4KB一页为单位,共24576页,对每一页使用1bit表示是否被占用,这个位图也存放在用于文件系统管理的4MB中。由于文件分页存储,用FAT表显式表达文件占用的数据页的跳转情况。

每个文件和文件夹都占用一个inode,inode内记录当前文件类型(目录还是可读写文件),父节点、左右兄弟节点(这个下面解释)、子结点的inode编号以及对应的FCB编号。

FCB用于记录文件名,一开始的设想是包含软、硬链接的功能,因此FCB的设定数量上限为inode的两倍,但实际实现起来过于复杂,FCB与inode一一对应

 4MB管理核心结构:

文件逻辑设计

如果区分一个inode是目录还是文件,对应不同类型的FCB,管理起来十分混乱,并且如果设置文件FCB和目录FCB,两种FCB储存的信息大小不一致,也不方便读取,因此采用所有文件都包含子结点inode编号的方式。(反正没有软硬链接要求,怎么方便怎么来)

由于这种结构下的文件目录是一棵多叉树,不确定一个目录下有多少个子结点,因此采用“孩子兄弟表示法”,图示:

用到的常量及数据结构

常量声明:

// 一个数据块大小
#define BLOCK_SIZE 4096

// 96MB对应24576个数据块
#define BLOCK_NUM 24576

// 每块对应1bit, 需要3072bytes表示
#define BLOCK_MAP_LENGTH 3072

// inode最多每块一个, 共24576个
#define INODE_MAP_LENGTH 3072

// FCB考虑后续可能有硬链接、软链接等, 开多一倍
#define FCB_MAP_LENGTH 6144

// 硬盘管理核心占4MB(剩余96MB)
#define CORE_SIZE (1 << 22)

下面是用到的数据结构:

// 32 bytes
struct Inode {
    int file_type; // 文件类型, 0是文件夹, 1是可读写文件
    int iblock; // 文件数据块起始下标(在FAT表中进行跳转)
    int size; // 文件大小, 可在touch创建文件时指定, 可大于内容长度
    int parent_inode_number; // 父节点(当前所处文件夹)inode下标
    int child_inode_number; // 第一个子节点下标
    int brother_inode_number_left; // 左兄弟节点inode下标
    int brother_inode_number_right; // 右兄弟inode下标
    int FCB_number; // 该文件对应FCB下标
};

// 16 bytes
struct FCB {
    int inode; // 该FCB对应inode下标
    char FileName[12]; // 文件名
};

// 4KB
union BlockMap {
    char block_map[BLOCK_MAP_LENGTH];
    char temp[BLOCK_SIZE]; // 撑开一个数据块
};

// 789504 bytes
struct InodeArray {
    char inode_map[INODE_MAP_LENGTH];
    struct Inode inode_array[BLOCK_NUM];
};

// 792576 bytes
struct FCBArray {
    char FCB_map[FCB_MAP_LENGTH];
    struct FCB FCB_array[BLOCK_NUM << 1];
};

// 790528 bytes -> 772KB -> 193 * 4KB
union InodeArrayBlock {
    struct InodeArray inode_array;
    char temp[790528];
};

// 194 * 4KB
union FCBArrayBlock {
    struct FCBArray fcb_array;
    char temp[794624];
};

// 1648 KB + 8 bytes
struct SystemCore {
    int block_used; // 已使用的数据块, 
    int block_rest; // 剩余空闲的数据块, 
    union BlockMap bit_map; // 4KB
    union InodeArrayBlock inode_array; // 193 * 4KB
    union FCBArrayBlock FCB_array; // 194 * 4KB
    int FAT[24576]; // 96KB
};

// 4MB
union SystemCore_union {
    struct SystemCore core;
    char temp[1 << 22];
};

// 管理信号量的数据结构
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *arry;
};

(ps:好几个地方用了union为了撑开一页,实际上没必要,后面写接口调用起来也麻烦。本来打算再包多一层,把100MB都放在一个结构体内,懒了)

一些基础功能接口(从小到大)

对位图进行操作(位运算)

// 查看1bytes, 即8bit中哪一位为0(0表示可用)
int searchBit(char byte) {
    int res = 0;
    while (byte < 0) {
        res++;
        byte <<= 1;
    }
    return res < 8 ? res : -1;
}

// 查找一个位图中, 第一个为0的bit的下标(0表示可用)
int searchFirstBit(char *bytes, int length) {
    int res, count = 0;
    while ((res = searchBit(*bytes)) == -1) {
        count++;
        if (count == length)
            break;
    }
    return count == length ? -1 : res + (count << 3);
}

// 设置一个位图中第pos位的bit
void setBit(char *bytes, int pos, int val) {
    while (pos / 8) {
        pos -= 8;
        bytes++;
    }
    char new_val = 1 << (7 - pos);
    if (val == 0) {
        new_val = ~new_val;
        *bytes = *bytes & new_val;
    }
    else {
        *bytes = *bytes | new_val;
    }
}

对数据块进行操作(释放,申请,调用上面的位图控制函数实现)

// 循环释放以iblock开始的数据块(操作位图实现)
void freeMemBlock(int iblock, union SystemCore_union *system_core) {
    int *FAT = system_core->core.FAT;
    while (iblock != -1) {
        setBit(system_core->core.bit_map.block_map, iblock, 0);
        iblock = FAT[iblock];
        system_core->core.block_used--;
        system_core->core.block_rest++;
    }
}

// 申请block_num个数据块, 自动连接FAT表, 返回起始数据块下标
int allocMemBlock(int block_num, union SystemCore_union *system_core) {
    if (block_num > system_core->core.block_rest) {
        printf("FAIL: no enough memory block.\n");
        return -1;
    }
    system_core->core.block_used += block_num;
    system_core->core.block_rest -= block_num;

    int block_number = searchFirstBit(system_core->core.bit_map.block_map, BLOCK_MAP_LENGTH);
    int res = block_number;
    block_num--;
    int temp = block_number;
    setBit(system_core->core.bit_map.block_map, block_number, 1);
    while (block_num > 0) {
        block_number = searchFirstBit(system_core->core.bit_map.block_map, BLOCK_MAP_LENGTH);
        system_core->core.FAT[temp] = block_number;
        temp = block_number;
        setBit(system_core->core.bit_map.block_map, block_number, 1);
        block_num--;
    }
    system_core->core.FAT[temp] = -1;
    return res;
}

文件创建与删除

有了位图和数据块的控制函数,文件的创建和删除就好办了。由于一块4096byte,测试的时候也不方便输太长的字符串,所以设置成文件的大小可大于内容的大小(文件大小4097byte,但内容为空也是允许的),这样方便创建文件时检测数据块分配是否正常。(修改文件时,如果发现新的内容长度大于文件大小,会重新分配足够的空间,后面会放)

// 删除文件
void remove_file(struct Inode *inode, union SystemCore_union *system_core) {
    
    int FCB_number = inode->FCB_number;
    struct FCB *fcb = &system_core->core.FCB_array.fcb_array.FCB_array[FCB_number];
    int inode_number = fcb->inode;

    freeMemBlock(inode->iblock, system_core); // 释放对应的数据块
    if (inode->brother_inode_number_left == -1) { // 如果是当前文件夹下第一个文件
        int father_inode_number = inode->parent_inode_number; // 右兄弟充当当前文件夹第一个孩子
        struct Inode *father_inode = &system_core->core.inode_array.inode_array.inode_array[father_inode_number];
        father_inode->child_inode_number = inode->brother_inode_number_right;

        int brother_right_inode_number = inode->brother_inode_number_right; // 右兄弟左指针清空
        struct Inode *brother_right_inode = &system_core->core.inode_array.inode_array.inode_array[brother_right_inode_number];
        brother_right_inode->brother_inode_number_left = -1;
    }
    else {
        int brother_inode_number = inode->brother_inode_number_left; // 左兄弟指向右兄弟
        struct Inode *brother_inode = &system_core->core.inode_array.inode_array.inode_array[brother_inode_number];
        brother_inode->brother_inode_number_right = inode->brother_inode_number_right;

        int brother_right_inode_number = inode->brother_inode_number_right; // 右兄弟指向左兄弟
        struct Inode *brother_right_inode = &system_core->core.inode_array.inode_array.inode_array[brother_right_inode_number];
        brother_right_inode->brother_inode_number_left = brother_inode_number;
    }
    setBit(system_core->core.inode_array.inode_array.inode_map, inode_number, 0); // 释放inode
    setBit(system_core->core.FCB_array.fcb_array.FCB_map, FCB_number, 0); // 释放FCB
}

// 根据文件名、文件大小创建文件
void touch(struct FCB *dir_now, char file_name[], union SystemCore_union *system_core, int file_size) {
    // 可能当前剩余块不够用
    int block_to_use = file_size / BLOCK_SIZE + 1;
    if (block_to_use > system_core->core.block_rest) {
        printf("FAIL: the file is too large.\n");
        return;
    }
    system_core->core.block_used += block_to_use;
    system_core->core.block_rest -= block_to_use;

    // 获取当前文件夹下最后一个文件的inode编号
    int last_childe_inode_number = system_core->core.inode_array.inode_array.inode_array[dir_now->inode].child_inode_number;
    if (last_childe_inode_number != -1)
        while (system_core->core.inode_array.inode_array.inode_array[last_childe_inode_number].brother_inode_number_right != -1)
            last_childe_inode_number = system_core->core.inode_array.inode_array.inode_array[last_childe_inode_number].brother_inode_number_right;

    // 为新文件夹获取inode
    int new_file_inode_number = searchFirstBit(system_core->core.inode_array.inode_array.inode_map, INODE_MAP_LENGTH);
    if (new_file_inode_number == -1) {
        printf("FAIL: All inode have been used!\n");
        return;
    }
    setBit(system_core->core.inode_array.inode_array.inode_map, new_file_inode_number, 1);

    // 获取inode后, 初始化inode信息
    struct Inode *new_file_inode = &system_core->core.inode_array.inode_array.inode_array[new_file_inode_number];
    new_file_inode->file_type = 1;
    new_file_inode->parent_inode_number = dir_now->inode;
    new_file_inode->brother_inode_number_left = -1;
    new_file_inode->brother_inode_number_right = -1;
    new_file_inode->child_inode_number = -1;
    new_file_inode->size = file_size;
    if (last_childe_inode_number != -1) {
        setBit(system_core->core.inode_array.inode_array.inode_map, new_file_inode_number, 0);
        new_file_inode->brother_inode_number_left = last_childe_inode_number;
        system_core->core.inode_array.inode_array.inode_array[last_childe_inode_number].brother_inode_number_right = new_file_inode_number; // 新文件装入当前文件夹(连接在最后一个孩子后面)
    }
    else
        system_core->core.inode_array.inode_array.inode_array[dir_now->inode].child_inode_number = new_file_inode_number;

    // 分配数据块,默认分配一块
    new_file_inode->iblock = allocMemBlock(block_to_use, system_core);
    writeFile(new_file_inode, system_core, ""); // 清空文件内容

    // 获取FCB
    int new_file_fcb_number = searchFirstBit(system_core->core.FCB_array.fcb_array.FCB_map, FCB_MAP_LENGTH);
    if (new_file_fcb_number == -1) {
        printf("FAIL: All FCB have been used!\n");
        return;
    }
    setBit(system_core->core.FCB_array.fcb_array.FCB_map, new_file_fcb_number, 1);
    new_file_inode->FCB_number = new_file_fcb_number;

    struct FCB *new_file_fcb = &system_core->core.FCB_array.fcb_array.FCB_array[new_file_fcb_number];
    new_file_fcb->inode = new_file_inode_number;
    strncpy(new_file_fcb->FileName, file_name, 12);
}

文件的读取和修改

修改是覆盖写入,个人写的是一个一个字节(也就是字符)读取/写入,其实可以一次读4096字节,因为一个数据块一定只属于一个文件,哪怕有浪费。(这部分写的好丑qaq)

// 读取文件内容, 放入data中
void readFile(struct Inode *inode, union SystemCore_union *system_core, char data[]) {
    char *data_start = (void *)system_core;
    data_start += CORE_SIZE; // 定位到数据块开始位置
    int count = 1, block_number = inode->iblock, write_pos = 0;
    int *FAT = system_core->core.FAT;
    char *read_p = data_start + block_number * BLOCK_SIZE;

    while (*read_p != 0) { // 读取到结束符退出
        data[write_pos++] = *read_p;
        read_p++;
        count++;

        if (count == BLOCK_SIZE) { // 读取完一个数据块, 跳转到下一个
            count = 1;
            block_number = FAT[block_number];
            read_p = data_start + block_number * BLOCK_SIZE;
        }
    }
    data[write_pos] = *read_p;
}

// 把data中的内容写入文件对应的数据块
void writeFile(struct Inode *inode, union SystemCore_union *system_core, char data[]) {
    int block_num = inode->size / 4096 + 1;

    if (block_num * 4096 <= strlen(data)) { // 如果这个文件的大小不足以装下data, 重新分配
        block_num = strlen(data) / 4096 + 1;
        int temp = allocMemBlock(block_num, system_core);
        if (temp == -1)
            return;
        freeMemBlock(inode->iblock, system_core);
        inode->iblock = temp;
        inode->size = strlen(data);
    }

    char *data_start = (void *)system_core;
    data_start += CORE_SIZE;
    int read_pos = 0, count = 1, block_number = inode->iblock;
    int *FAT = system_core->core.FAT;
    char *write_p = data_start + block_number * BLOCK_SIZE;
    while (data[read_pos] != 0) { // 类似文件读取
        *write_p = data[read_pos];
        write_p++;
        read_pos++;
        count++;

        if (count == BLOCK_SIZE) {
            count = 1;
            block_number = FAT[block_number];
            write_p = data_start + block_number * BLOCK_SIZE;
        }
    }
    *write_p = 0;
    if (inode->size < strlen(data))
        inode->size = strlen(data);
}

文件夹的创建和删除

创建文件简单多了,分配FCB和inode即可。删除文件夹就是普通递归,如果文件夹为空,直接删除;否则遍历孩子,空文件夹或文件直接删除,非空文件夹递归调用。

// 在当前文件夹下创建名为dir_name的文件夹
void mkdir(struct FCB *dir_now, char dir_name[], union SystemCore_union *system_core) {
    // 获取当前文件夹下最后一个文件的inode编号
    int last_childe_inode_number = system_core->core.inode_array.inode_array.inode_array[dir_now->inode].child_inode_number;
    if (last_childe_inode_number != -1) // 可能当前文件夹为空
        while (system_core->core.inode_array.inode_array.inode_array[last_childe_inode_number].brother_inode_number_right != -1)
            last_childe_inode_number = system_core->core.inode_array.inode_array.inode_array[last_childe_inode_number].brother_inode_number_right;

    // 为新文件夹获取可用的inode
    int new_dir_inode_number = searchFirstBit(system_core->core.inode_array.inode_array.inode_map, INODE_MAP_LENGTH);
    if (new_dir_inode_number == -1) {
        printf("FAIL: All inode have been used!\n");
        return;
    }
    setBit(system_core->core.inode_array.inode_array.inode_map, new_dir_inode_number, 1);

    // 获取inode后, 初始化inode信息
    struct Inode *new_dir_inode = &system_core->core.inode_array.inode_array.inode_array[new_dir_inode_number];
    new_dir_inode->file_type = 0; // 文件夹类型为0
    new_dir_inode->parent_inode_number = dir_now->inode;
    new_dir_inode->brother_inode_number_left = -1;
    new_dir_inode->brother_inode_number_right = -1;
    new_dir_inode->child_inode_number = -1;
    if (last_childe_inode_number != -1) { // 如果当前文件夹不为空, 挂在最后一个孩子后
        new_dir_inode->brother_inode_number_left = last_childe_inode_number;
        system_core->core.inode_array.inode_array.inode_array[last_childe_inode_number].brother_inode_number_right = new_dir_inode_number; // 新文件夹装入当前文件夹(连接在最后一个孩子后面)
    }
    else // 当前文件夹为空, 直接挂在当前文件夹的child_inode, 作为第一个孩子
        system_core->core.inode_array.inode_array.inode_array[dir_now->inode].child_inode_number = new_dir_inode_number;

    // 获取可用的FCB
    int new_dir_fcb_number = searchFirstBit(system_core->core.FCB_array.fcb_array.FCB_map, FCB_MAP_LENGTH);
    if (new_dir_fcb_number == -1) {
        setBit(system_core->core.inode_array.inode_array.inode_map, new_dir_inode_number, 0);
        printf("FAIL: All FCB have been used!\n");
        return;
    }
    setBit(system_core->core.FCB_array.fcb_array.FCB_map, new_dir_fcb_number, 1);
    new_dir_inode->FCB_number = new_dir_fcb_number;

    // 初始化FCB
    struct FCB *new_dir_fcb = &system_core->core.FCB_array.fcb_array.FCB_array[new_dir_fcb_number];
    new_dir_fcb->inode = new_dir_inode_number;
    strncpy(new_dir_fcb->FileName, dir_name, 12);
}

// 删除文件夹
void remove_dir(struct Inode *inode, union SystemCore_union *system_core) {

    int FCB_number = inode->FCB_number;
    struct FCB *fcb = &system_core->core.FCB_array.fcb_array.FCB_array[FCB_number];
    int inode_number = fcb->inode;

    while (inode->child_inode_number != -1) { // 如果文件夹不为空
        struct Inode *child_inode = &system_core->core.inode_array.inode_array.inode_array[inode->child_inode_number];
        if (child_inode->file_type == 1) // 孩子是文件直接删除
            remove_file(child_inode, system_core);
        else // 孩子是文件夹, 递归删除
            remove_dir(child_inode, system_core);
    }
    // 文件夹已清空, 下面与普通文件删除过程一样
    if (inode->brother_inode_number_left == -1) {
        int father_inode_number = inode->parent_inode_number;
        struct Inode *father_inode = &system_core->core.inode_array.inode_array.inode_array[father_inode_number];
        father_inode->child_inode_number = inode->brother_inode_number_right;

        int brother_right_inode_number = inode->brother_inode_number_right;
        struct Inode *brother_right_inode = &system_core->core.inode_array.inode_array.inode_array[brother_right_inode_number];
        brother_right_inode->brother_inode_number_left = -1;
    }
    else {
        int brother_inode_number = inode->brother_inode_number_left;
        struct Inode *brother_inode = &system_core->core.inode_array.inode_array.inode_array[brother_inode_number];
        brother_inode->brother_inode_number_right = inode->brother_inode_number_right;

        int brother_right_inode_number = inode->brother_inode_number_right;
        struct Inode *brother_right_inode = &system_core->core.inode_array.inode_array.inode_array[brother_right_inode_number];
        brother_right_inode->brother_inode_number_left = brother_inode_number;
    }
    setBit(system_core->core.inode_array.inode_array.inode_map, inode_number, 0);
    setBit(system_core->core.FCB_array.fcb_array.FCB_map, FCB_number, 0);
}

cd和ls指令

cd这个基础接口只实现了进入子目录,在外面的包装函数实现返回上一层目录。ls指令遍历当前目录下的孩子节点即可。

// cd进入指定的子目录
struct FCB* cd(struct FCB *dir_now, char file_name[], union SystemCore_union *system_core) {
    struct Inode *dir_now_inode = &system_core->core.inode_array.inode_array.inode_array[dir_now->inode];
    int child_inode_number = dir_now_inode->child_inode_number;

    // 遍历当前文件夹的子inode, 查看是否有同名的文件夹,有则返回
    while (child_inode_number != -1) {
        struct Inode *child_inode = &system_core->core.inode_array.inode_array.inode_array[child_inode_number];
        int child_FCB_number = child_inode->FCB_number;
        struct FCB *child_FCB = &system_core->core.FCB_array.fcb_array.FCB_array[child_FCB_number];
        if (child_inode->file_type == 0 && strncmp(child_FCB->FileName, file_name, 12) == 0)
            return child_FCB;
        child_inode_number = child_inode->brother_inode_number_right;
    }
    return NULL;
}

// 列出当前文件夹下子目录和文件的信息(文件inode编号, 文件类型, 文件大小, 文件名)
void ls(struct FCB *dir_now, union SystemCore_union *system_core) {
    struct Inode *dir_now_inode = &system_core->core.inode_array.inode_array.inode_array[dir_now->inode];
    int child_inode_number = dir_now_inode->child_inode_number;
    while (child_inode_number != -1) {
        struct Inode *child_inode = &system_core->core.inode_array.inode_array.inode_array[child_inode_number];
        printf("inode:%d file_type:%d file_size:%d %s\n", child_inode_number, child_inode->file_type, child_inode->size, system_core->core.FCB_array.fcb_array.FCB_array[child_inode->FCB_number].FileName);
        child_inode_number = child_inode->brother_inode_number_right;
    }
}

其他辅助功能函数

其实就获取当前FCB所在的完整路径(向上递归到根目录),和根据文件类型和名字在当前目录下查找是否存在。(根据函数名看的出来啦)

// 递归获取当前目录的路径
void getPath(struct FCB *dir_now, union SystemCore_union *system_core, char res[]) {
    if (dir_now->inode != 0) {
        int father_inode_number = system_core->core.inode_array.inode_array.inode_array[dir_now->inode].parent_inode_number;
        int father_FCB_number = system_core->core.inode_array.inode_array.inode_array[father_inode_number].FCB_number;
        struct FCB *father_FCB = &system_core->core.FCB_array.fcb_array.FCB_array[father_FCB_number];
        getPath(father_FCB, system_core, res);
    }
    strncat(res, dir_now->FileName, 12);
    strcat(res, "/");
}

// 在当前目录下搜索是否有指定名称与文件类型的孩子
struct Inode* serachInodeByName(struct FCB *dir_now, char name[], int file_type, union SystemCore_union *system_core) {
    struct Inode *res = NULL;
    struct Inode *dir_now_inode = &system_core->core.inode_array.inode_array.inode_array[dir_now->inode];
    int child_inode_number = dir_now_inode->child_inode_number;
    while (child_inode_number != -1) { // 循环遍历所有孩子
        struct Inode *child_inode = &system_core->core.inode_array.inode_array.inode_array[child_inode_number];
        int child_FCB_number = child_inode->FCB_number;
        struct FCB *child_FCB = &system_core->core.FCB_array.fcb_array.FCB_array[child_FCB_number];
        if (child_inode->file_type == file_type && strncmp(child_FCB->FileName, name, 12) == 0)
            return child_inode;
        child_inode_number = child_inode->brother_inode_number_right;
    }
    return res;
}

进程同步

实现读写文件时进程同步,用的是无名信号量,这里参考了文章(Linux C 信号量_xiaozhu丶的博客-CSDN博客_linuxc 信号量),只需要在创建信号量集的时候创建数量与inode相同的信号量即可

sem_id = semget(0x8080, BLOCK_NUM, 0660 | IPC_CREAT); // 创建信号量集
union semun sem_union;
sem_union.val = 1;
for (int i = 0; i < BLOCK_NUM; i++) // 初始化信号量
    semctl(sem_id, i, SETVAL, sem_union);

然后封装一下P/V操作的函数

// inode_number即信号量集中该文件对应的信号量的下标, 这里等待信号量为1, 获取到后上锁, 信号量置0
void wait(int inode_number) {
    struct sembuf sem_b;
    sem_b.sem_num = inode_number;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    semop(sem_id, &sem_b, 1);
}

// 信号量置1
void notify(int inode_number) {
    struct sembuf sem_b;
    sem_b.sem_num = inode_number;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;
    semop(sem_id, &sem_b, 1);
}

sem_buf中的sem_num是信号量集中指定信号量的下标,使用起来非常方便(不过在服务器上运行时,无法成功创建这个信号量集,可能是信号量集过大?需要进一步求证)

为实现题目要求的同步效果,读写操作在不同位置释放信号量即可

​​​​​​​               

剩下的就是写一个初始化进程用于创建100MB共享内存,初始化数据结构的内容,创建信号量集和根目录。另写一个shell程序,对指令进行处理,包装一下上述基础功能即可。

总结

虽然写的过程中完全没考虑效率问题,有些地方(特指文件读写)写的很乱,不是翔味巧克力就是巧克力味的翔,但是莫名还是很想记录一下。虽然上了一学期,对OS很感兴趣,但真是深似海啊qaq。(好了写完去赶算法报告,寄)

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值