当前位置: 首页 > news >正文

lab7 thread

image-20230825171259440

文章目录

  • Uthread: switching between threads
    • task
    • hints
    • 思路
      • 上下文的恢复和保存
      • thread_create
      • thread_schedule
  • Using threads
    • 思路
  • Barrier

Uthread: switching between threads

在这个练习中,你将为一个用户级别线程系统设计上下文切换机制,并实现它。

task

你的任务是提出一个计划,并实现它

  1. 创造线程
  2. 切换线程的时候,保存和恢复寄存器

当你完成的时候,make grade会显示你通过了uthreadtest

你将需要在user/uthread.c中的thread_create()thread_schedule(),在user/uthread_switch.Sthread_switch添加代码

  1. 一个目标是去保证,当thread_schedule()第一次运行一个线程时,这个线程会在它自己的栈上执行传递给thread_create的函数

  2. 另一个目标是去保证thread_switch保存被切换线程的寄存器,恢复被恢复线程的寄存器,并且到被恢复线程上次被中断的地方继续执行。

  3. 你将不得不决定将寄存器存放在哪里,修改struct thread去持有寄存器是不错的想法

  4. 你需要在thread_schedule调用thread_switch

  5. 你可以传递任何你需要的参数给thread_switch,但是目标就是切换线程

hints

  1. thread_switch只需要保存和恢复被调用函数保护寄存器
  2. 你可以在user/uthread.asm中看到uthread的汇编代码

思路

代码非常少,主要是要搞清楚整个流程。线程的切换主要就是通过一个ra寄存器记录切换后函数从哪开始执行,通过一个sp寄存器记录切换之后栈的地址,然后就是一些被调用者保护寄存器。

为什么只需要保存callee保护寄存器?

因为switch函数就是一个普通的c函数,在调用它的时候,调用函数会将调用者保护寄存器压入栈中保存,在它返回之后,会从>栈中恢复被调用者保护寄存器。在switch结束之后,通过栈就可以恢复caller寄存器(这也是为什么要保存和恢复sp指针)。

而对于callee保护寄存器,就是被调用的函数来保护的了。也就是说,通过ra,sp以及callee保护寄存器,我们就可以恢复到某>个线程的某个函数执行之后的镜像,缺一不可。

对于第一次被调度的进程,就更无所谓了,反正也不需要恢复什么caller和callee寄存器,本质上只需要ra和sp即可,但是为了统>一写法,操作一下callee寄存器也没问题

上下文的恢复和保存

而在我们的这个task中,线程切换时也要用到上述功能,因此需要模仿xv6构建一个context的结构体,并将其加入到thread的定义中

struct 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;
};

然后修改uthread_switch的定义为extern void thread_switch(struct context *, struct context *);,并将上下文保存和恢复的汇编加入对应的汇编文件

	.text/** save the old thread's registers,* restore the new thread's registers.*/.globl thread_switch
thread_switch:/* YOUR CODE HERE */sd ra, 0(a0)sd sp, 8(a0)sd s0, 16(a0)sd s1, 24(a0)sd s2, 32(a0)sd s3, 40(a0)sd s4, 48(a0)sd s5, 56(a0)sd s6, 64(a0)sd s7, 72(a0)sd s8, 80(a0)sd s9, 88(a0)sd s10, 96(a0)sd s11, 104(a0)ld ra, 0(a1)ld sp, 8(a1)ld s0, 16(a1)ld s1, 24(a1)ld s2, 32(a1)ld s3, 40(a1)ld s4, 48(a1)ld s5, 56(a1)ld s6, 64(a1)ld s7, 72(a1)ld s8, 80(a1)ld s9, 88(a1)ld s10, 96(a1)ld s11, 104(a1)ret    /* return to ra */

thread_create

在这里,我们需要设置ra和sp寄存器,分别指向函数的入口地址和栈的初始地址。其中栈的地址应该定位在栈的最高地址,因为它向下增长

    // YOUR CODE HEREt->ctx.ra = (uint64)func;t->ctx.sp = (uint64)t->stack + STACK_SIZE - 1;

thread_schedule

最后在这个函数中加入一行即可

        /* YOUR CODE HERE* Invoke thread_switch to switch from t to next_thread:* thread_switch(??, ??);*/thread_switch(&t->ctx, &current_thread->ctx);

这个task自己要写的代码非常少,但是uthread.c整个文件可以说包含了上下文切换最关键的部分了,很值得学习。

并且原来在用户态,也可以在c代码里面嵌入汇编代码,神奇。

Using threads

首先,为了避免插入时出错,你需要在putget中使用锁,如果能够在make grade中通过ph_safe,就说明成功

pthread_mutex_t lock;            // declare a lock
pthread_mutex_init(&lock, NULL); // initialize the lock
pthread_mutex_lock(&lock);       // acquire lock
pthread_mutex_unlock(&lock);     // release lock

然后你应该优化你的代码,使得你能通过ph_fast的测试,你可以在每个桶上添加一个锁。两个线程至少要达到1.25倍的速度

思路

直接一步到位了,给每个bucker设置一个锁,并在main函数中对锁初始化

pthread_mutex_t locks[NBUCKET];void init_lock() {for (int i = 0; i < NBUCKET; i++) {pthread_mutex_init(&locks[i], NULL);}
}

然后构造两个宏,省的后面输入一大串

#define LOCK(i) (pthread_mutex_lock(&locks[i]));
#define UNLOCK(i) (pthread_mutex_unlock(&locks[i]));

最后在put和get的起始和末尾都加上一个LOCK(i)UNLOC(i)

image-20230825163234832

Barrier

这部分的实验文档看得我迷迷糊糊的,还是看了半天源代码才看懂是啥意思。

关键就是下面这个函数,我们每一次for循环,bstate.round都应该和循环轮数相同。再结合实验文档可以知道,就是要求我们通过barrier实现所有线程都在同一次for循环里,不能有人提前进入下一轮,因为这样的话,这个assert肯定就要错了。

static void *
thread(void *xa) {long n = (long)xa;long delay;int i;for (i = 0; i < 20000; i++) {int t = bstate.round;assert(i == t);barrier();usleep(random() % 100);}return 0;
}

然后就是这个结构体,它是关键。其中round代表的就是现在for循环的轮数,而nthread代表的是目前已经有多少个线程到达了屏障正在阻塞等待,然后上面就是两个锁,一个是常规的互斥锁,一个是条件变量

struct barrier {pthread_mutex_t barrier_mutex;pthread_cond_t barrier_cond;int nthread; // Number of threads that have reached this round of the barrierint round;   // Barrier round
} bstate;

条件变量的使用也很有意思。第一个wait操作,要求这个线程必须持有锁,然后调用wait之后,这个线程会释放这个锁,然后进入阻塞睡眠。第二个广播操作,会将通过cond阻塞的所有线程都唤醒。

pthread_cond_wait(&cond, &mutex);  // go to sleep on cond, releasing lock mutex, acquiring upon wake up
pthread_cond_broadcast(&cond);     // wake up every thread sleeping on cond

上面两个锁的组合就可以构建barrier函数。有一些宏定义,方便使用。

首先,每个进入barrier的线程都应该将现在进入barrier的线程数量加1。而为了防止并发带来的问题,+1的过程肯定是要用锁的,我们这里正好就是用了barrier_mutex。

然后,我们需要判断目前的数量是否已经达到了线程总数nthread

  1. 如果没达到,那就通过条件变量让它睡觉去吧
  2. 如果达到了,那么我们需要将所有因此阻塞的进程都唤醒
    1. 但是在唤醒之前,我们需要先将bstate的round和nthread变量给更新了
    2. 如果我们是在唤醒之后更新,那么可能cpu瞬间就被别人抢去了,然后那些人就进入了下一轮for循环,直接assert失败。

还有一种很恶心的并发问题,就是如果我们很早就UNLOCK了,那么有可能某个线程还没有wait,就有一个线程调用了广播,那么后果就是这个线程永远不会被唤醒。不过在我们这里是不会出现这种情况的。

#define LOCK() (pthread_mutex_lock(&bstate.barrier_mutex))
#define UNLOCK() (pthread_mutex_unlock(&bstate.barrier_mutex))
#define WAIT() (pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex))
#define BROADCAST() (pthread_cond_broadcast(&bstate.barrier_cond))
static void
barrier() {// YOUR CODE HERE//// Block until all threads have called barrier() and// then increment bstate.round.//LOCK();bstate.nthread += 1;if (bstate.nthread < nthread) {WAIT();} else {bstate.round += 1;bstate.nthread = 0;BROADCAST();}UNLOCK();
}

相关文章:

lab7 thread

文章目录 Uthread: switching between threadstaskhints思路上下文的恢复和保存thread_createthread_schedule Using threads思路 Barrier Uthread: switching between threads 在这个练习中&#xff0c;你将为一个用户级别线程系统设计上下文切换机制&#xff0c;并实现它。 …...

接口自动化测试:mock server之Moco工具

什么是mock server mock&#xff1a;英文可以翻译为模仿的&#xff0c;mock server是我们用来解除依赖&#xff08;耦合&#xff09;&#xff0c;假装实现的技术&#xff0c;比如说&#xff0c;前端需要使用某些api进行调试&#xff0c;但是服务端并没有开发完成这些api&#…...

用python从零开始做一个最简单的小说爬虫带GUI界面(2/3)

目录 前一章博客 前言 主函数的代码实现 逐行代码解析 获取链接 获取标题 获取网页源代码 获取各个文章的链接 函数的代码 导入库文件 获取文章的标题 获取文章的源代码 提取文章目录的各个文章的链接 总代码 下一章内容 前一章博客 用python从零开始做一个最简单…...

CEF 缓存处理:清理缓存、禁用缓存、忽略缓存

目录 一、CEF缓存处理 1、指定缓存路径 2、清理缓存 3、禁用缓存 1)、原理分析...

Android 系统桌面 App —— Launcher 开发(1)

Android 系统桌面 App —— Launcher 开发&#xff08;1&#xff09; Launcher简介 Launcher就是Android系统的桌面&#xff0c;俗称“HomeScreen”也就是我们开机后看到的第一个App。launcher其实就是一个app&#xff0c;它的作用是显示和管理手机上其他App。目前市场上有很…...

一个程序员的工作日记--每天就干两件事,一年后让别人刮目相看

文章目录 成功源于专注一、早上布局二、晚上复盘三、技术细节四、专注与成功五、专注的重要性六、忙碌和赚钱七、结论以嵌入式开发为例&#xff1a;一、早上布局二、晚上复盘三、技术细节四、专注与成功五、忙碌和赚钱六、结论在嵌入式软件开发中&#xff0c;我们需要按照以下步…...

Linux虚拟机安装(Ubuntu 20)

最近这段时间使用VMWare安装了一下Ubuntu版本的Linux虚拟机&#xff0c;在这里记录一下安装时参考的文章以及需要注意的细节 参考链接&#xff1a; VMware虚拟机下安装Ubuntu20.04&#xff08;保姆级教程&#xff09; 一、安装VMWare 下载链接&#xff1a;VMware Workstatio…...

1.6 服务器处理客户端请求

客户端进程向服务器进程发送一段文本&#xff08;MySQL语句&#xff09;&#xff0c;服务器进程处理后再向客户端进程发送一段文本&#xff08;处理结果&#xff09;。 从图中我们可以看出&#xff0c;服务器程序处理来自客户端的查询请求大致需要经过三个部分&#xff0c;分别…...

火山引擎发布自研视频编解码芯片 压缩效率提升30%

8月22日&#xff0c;火山引擎视频云宣布其自研的视频编解码芯片已成功出片。经验证&#xff0c;该芯片的视频压缩效率相比行业主流硬件编码器可提升30%以上&#xff0c;未来将服务于抖音、西瓜视频等视频业务&#xff0c;并将通过火山引擎视频云开放给企业客户。 火山引擎总裁…...

从头开始:将新项目上传至Git仓库的简易指南

无论您是一个经验丰富的开发者还是一个刚刚起步的新手&#xff0c;使用Git来管理您的项目是一个明智的选择。Git是一个强大的版本控制系统&#xff0c;它可以帮助您跟踪项目的变化、合并代码以及与团队成员协作。在本文中&#xff0c;我们将为您提供一步步的指南&#xff0c;教…...

数据库的增量备份与差异备份

在当今数字时代&#xff0c;数据已经成为公司的主要资产。为了维护这些珍贵的数据&#xff0c;公司通常会采取各种数据保护措施&#xff0c;其中增量备份是一种很有效的方法。本文将详细介绍什么是数据库的增量备份&#xff0c;以及如何帮助企业更有效地维护数据。  我们需要…...

视频云存储/安防监控视频智能分析网关V3:占道经营功能详解

违规占道经营者经常会在人流量大、车辆集中的道路两旁摆摊&#xff0c;导致公路交通堵塞&#xff0c;给居民出行的造成不便&#xff0c;而且违规占路密集的地方都是交通事故频频发生的区域。 TSINGSEE青犀视频云存储/安防监控视频/AI智能分析网关V3运用视频AI智能分析技术&…...

卡尔曼滤波学习笔记

Kalman Filter Ⅰ、直观理解1、描述2、例子 Ⅱ、适用范围1、线性系统2、噪声服从高斯分布 Ⅲ、相关公式1、原始公式2、预测公式3、更新公式4、初值赋予5、总结 Ⅳ、应用例子Ⅴ、代码实现Ⅵ、公式理解1、协方差矩阵的理解1.1 协方差1.2 协方差矩阵1.3、相关数学公式 2、状态方程…...

NLP预训练模型超大规模探索

总共从四方面来进行比较。 第一个方面&#xff0c;高层次方法&#xff08;自监督的预训练方法&#xff09;对比&#xff0c;总共三种方式。 语言模型式&#xff0c;就是 GPT-2 那种方式&#xff0c;从左到右预测&#xff1b;BERT-style 式&#xff0c;就是像 BERT 一样将一部…...

OpenCV实战系列总目录(更新中)

1、openCV实战-系列教程1&#xff1a;基本操作&#xff08;环境配置/图像读取打印/视频读取打印/图像裁剪/颜色通道提取/边界填充/数值计算&#xff09;、源码解读 openCV实战-系列教程1&#xff1a;基本操作&#xff08;环境配置/图像读取打印/视频读取打印/图像裁剪/颜色通道…...

《华为认证》6to4自动隧道

实验需求&#xff1a; 在NE1和NE3之间使用tunnel 口创建6to4自动隧道&#xff0c;实现PC1和PC2互访。 步骤1:配置ipv4地址&#xff0c;如图所示&#xff1a; 步骤2&#xff1a;配置NE1和NE3的ipv4路由&#xff0c;是两端的ipv4网络能够互访 R1: ip route-static 0.0.0.0 0…...

Java课题笔记~Element UI

Element&#xff1a;是饿了么公司前端开发团队提供的一套基于 Vue 的网站组件库&#xff0c;用于快速构建网页。 Element 提供了很多组件&#xff08;组成网页的部件&#xff09;供我们使用。例如 超链接、按钮、图片、表格等等~ 如下图左边的是我们编写页面看到的按钮&#…...

[论文笔记]ON LAYER NORMALIZATION IN THE TRANSFORMER ARCHITECTURE

引言 这是论文ON LAYER NORMALIZATION IN THE TRANSFORMER ARCHITECTURE的阅读笔记。本篇论文提出了通过Pre-LN的方式可以省掉Warm-up环节,并且可以加快Transformer的训练速度。 通常训练Transformer需要一个仔细设计的学习率warm-up(预热)阶段:在训练开始阶段学习率需要设…...

h5逻辑_调用手机拨号功能

有时点击页面某个按钮&#xff0c;希望能掉起手机拨号页&#xff0c;实现步骤如下&#xff1a; [1] 在index.html中添加如下代码<meta name"format-detection" content"telephoneyes" />[2] 点击按钮调用函数callPhone (phoneNumber) {window.locat…...

字节一面:post为什么会发送两次请求?

前言 最近博主在字节面试中遇到这样一个面试题&#xff0c;这个问题也是前端面试的高频问题&#xff0c;因为在前端开发的日常开发中我们总是会与post请求打交道&#xff0c;一个小小的post请求也是牵扯到很多知识点的&#xff0c;博主在这给大家细细道来。 &#x1f680; 作者…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

基于鸿蒙(HarmonyOS5)的打车小程序

1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...