【MIT 6.S081】2020, 实验记录(7),Lab: Multithreading

2024-03-13 21:44

本文主要是介绍【MIT 6.S081】2020, 实验记录(7),Lab: Multithreading,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

    • Task 1: Uthread: switching between threads
    • Task 2:Using threads
    • Task 3:Barrier

Task 1: Uthread: switching between threads

这个实验是要求实现用户级线程的创建和调度,有点类似于有栈协程。非常有意思,值得多学习。

在完成这个实验前,需要了解 XV6 如何实现的进程的调度,然后通过在模拟进程切换的逻辑实现用户级线程的创建和切换。

在 kernel 调度进程时,会使用 context 来保存被挂起的进程的寄存器上下文,我们这里也需要一个类似的结构体来保存这些上下文(在 uthread.c 中声明):

// 模仿 kernel/proc.h 中的 struct context
// 保存用户线程的上下文
struct thread_context {uint64 ra;uint64 sp;// callee-saveduint64 s0;uint64 s1;uint64 s2;uint64 s3;uint64 s4;uint64 s5;uint64 s6;uint64 s7;uint64 s8;uint64 s9;uint64 s10;uint64 s11;
};

然后将我们声明的 thread_context 结构体放入 struct thread 中:

thread_context
thread_create() 中初始化这个字段,让其中的 ra 字段指向线程需要执行的函数(因为线程切换后会执行 ra 寄存器所指向的位置),让其中的栈指针指向合适的位置:

thread-create

然后模仿 kernel 中用来切换进程的 swtch 函数,实现线程切换时上下文的切换(也就是保存现有的各个寄存器值到 context 中,把新线程的 context 中保存的各个寄存器的值写入寄存器中),函数 thread_switch() 已经声明在了 uthread.c 中,但这部分的实现需要我们模仿 kernel/swtch.S 使用汇编语言实现在 uthread_switch.S 中:

uthread_switch.S
这个最后的 ret 会回到 ra 寄存器所指向的位置,也就是我们想让这个线程所执行的函数。

最后在线程调度的函数中加入 thread_switch() 的调用,参数就是现在线程和新线程的 context 指针:

在这里插入图片描述
至此,第一个 task 就完成了。

Task 2:Using threads

这个 task 就不是在 xv6 中写代码了,而是使用 Unix 提供的 pthread 及相关工具来实现一个并发安全的 hash map。

最简单的思路就是有一个 lock,每一次对 hash map 的读写都需要先获取这个 lock 再操作。但是这会存在效率问题,因为一个 map 有很多 buckets,而大多数情况下两个线程同时写 hash map 时涉及的 buckets 并没有关联。为了解决这个问题,可以让每个 bucket 都关联一个 lock,需要访问一个 bucket 时就需要先获取这个 bucket 所关联的 lock。

首先声明 locks,锁的数量与 bucket 的数量相同:

locks 声明

然后初始化 locks:

初始化 locks

然后在 hash map 的 get 和 put 函数操作内加锁。

get 函数中,首先计算出在 entry 哪个 bucket 中,然后对这个 bucket 相关联的 lock 上锁,操作完成后再解锁:

get 操作

put 函数也是类似:

put 函数

上面完成后,这个 task 就通过了:

task 2

Task 3:Barrier

最后一个 task 的难度也不大,主要考察 pthread 中条件变量的使用,task 是实现 barrier() 函数,一共有 n 个进程,每个进程调用了 barrier() 后会等待,直到所有 n 个进程都调用了 barrier() 后才能继续进行下去。

实现难度不大,利用好 mutex 和 cond 就行:

barrier
实现好这个函数后,就可以通过测试了。

task 3

这篇关于【MIT 6.S081】2020, 实验记录(7),Lab: Multithreading的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/806290

相关文章

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

Python UV安装、升级、卸载详细步骤记录

《PythonUV安装、升级、卸载详细步骤记录》:本文主要介绍PythonUV安装、升级、卸载的详细步骤,uv是Astral推出的下一代Python包与项目管理器,主打单一可执行文件、极致性能... 目录安装检查升级设置自动补全卸载UV 命令总结 官方文档详见:https://docs.astral.sh/

统一返回JsonResult踩坑的记录

《统一返回JsonResult踩坑的记录》:本文主要介绍统一返回JsonResult踩坑的记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录统一返回jsonResult踩坑定义了一个统一返回类在使用时,JsonResult没有get/set方法时响应总结统一返回

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

java对接海康摄像头的完整步骤记录

《java对接海康摄像头的完整步骤记录》在Java中调用海康威视摄像头通常需要使用海康威视提供的SDK,下面这篇文章主要给大家介绍了关于java对接海康摄像头的完整步骤,文中通过代码介绍的非常详细,需... 目录一、开发环境准备二、实现Java调用设备接口(一)加载动态链接库(二)结构体、接口重定义1.类型

apache的commons-pool2原理与使用实践记录

《apache的commons-pool2原理与使用实践记录》ApacheCommonsPool2是一个高效的对象池化框架,通过复用昂贵资源(如数据库连接、线程、网络连接)优化系统性能,这篇文章主... 目录一、核心原理与组件二、使用步骤详解(以数据库连接池为例)三、高级配置与优化四、典型应用场景五、注意事

SpringBoot实现文件记录日志及日志文件自动归档和压缩

《SpringBoot实现文件记录日志及日志文件自动归档和压缩》Logback是Java日志框架,通过Logger收集日志并经Appender输出至控制台、文件等,SpringBoot配置logbac... 目录1、什么是Logback2、SpringBoot实现文件记录日志,日志文件自动归档和压缩2.1、

qtcreater配置opencv遇到的坑及实践记录

《qtcreater配置opencv遇到的坑及实践记录》我配置opencv不管是按照网上的教程还是deepseek发现都有些问题,下面是我的配置方法以及实践成功的心得,感兴趣的朋友跟随小编一起看看吧... 目录电脑环境下载环境变量配置qmake加入外部库测试配置我配置opencv不管是按照网上的教程还是de

使用nohup和--remove-source-files在后台运行rsync并记录日志方式

《使用nohup和--remove-source-files在后台运行rsync并记录日志方式》:本文主要介绍使用nohup和--remove-source-files在后台运行rsync并记录日... 目录一、什么是 --remove-source-files?二、示例命令三、命令详解1. nohup2.

Java使用SLF4J记录不同级别日志的示例详解

《Java使用SLF4J记录不同级别日志的示例详解》SLF4J是一个简单的日志门面,它允许在运行时选择不同的日志实现,这篇文章主要为大家详细介绍了如何使用SLF4J记录不同级别日志,感兴趣的可以了解下... 目录一、SLF4J简介二、添加依赖三、配置Logback四、记录不同级别的日志五、总结一、SLF4J