首页 > 其他分享 >Xv6 Lab7: Multithreading

Xv6 Lab7: Multithreading

时间:2023-07-22 16:11:17浏览次数:57  
标签:uint64 ld thread Xv6 a1 a0 Lab7 Multithreading sd

Uthread: switching between threads

这个题还是对的起它 moderate 的难度了,如果认真看了 book-riscv-rev2.pdf 的 Scheduling 章节,以及看了这个 课程翻译,那么这题可以很快做出来,个人觉得 pdf 讲得更加清楚一些。

这个题甚至帮你把需要添加代码的地方都标注出来了,参照题目说明,主要有三步:

  1. 修改 thread_create 来保证当 thread_schedule 第一次运行 thread_create 创建出来的线程时,该线程就会在自己的 stack 上执行传递给 thread_create 的函数,这里我们可以参照 allocproc 的实现,在 thread_create 标记出来的要我们添加代码的地方添加如下三行:
memset(&t->context, 0, sizeof(t->context));
t->context.ra = (uint64)func;
t->context.sp = (uint64)t->stack + STACK_SIZE;
  1. 保证 thread_switch 会切换并保存寄存器,这里参照 scheduler 的实现即可,在注释标记的地方添加以下语句,并且在 uthread_switch.S 中实现 thread_switch 函数(照抄 swtch 即可):
thread_switch((uint64)&t->context, (uint64)&current_thread->context);
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 */
  1. 修改 strcut thread 来存储 thread_switch 时需要保存的寄存器,还是参照 struct proc 即可:
struct t_context {
    uint64 ra;
    uint64 sp;

    // callee saved
    uint64 s0;
    uint64 s1;
    uint64 s2;
    uint64 s3;
    uint64 s4;
    uint64 s5;
    uint64 s6;
    uint64 s7;
    uint64 s8;
    uint64 s9;
    uint64 s10;
    uint64 s11;
};

struct thread {
    char stack[STACK_SIZE]; /* the thread's stack */
    int state;              /* FREE, RUNNING, RUNNABLE */
    struct t_context context;
};

这样修改之后就能通过 uthread 了。

Using threads

首先,注意 include <pthread.h> 应该在文件内容的最前面,否则 make ph 时容易出现意料之外的问题。

在多线程执行 ph 时,之所以会出现 xxx keys missing,是因为写的时候,假设有两个 put 进程,keys 的数量一共为 $100$,那么进程 $1$ 会负责写 $0\sim 49$,进程 $2$ 会负责写 $50\sim 99$,NBUCKET = 5,那么两个进程会往同一个 bucket 中写入 entry,这就是出现问题的原因。

假设进程 $1$ 执行 insert(1, 3, &table[1], table[1]);,进程 $2$ 执行 insert(6, 2, &table[1], table[1]),就会出现类似 kalloc 的 freelist 中,两个进程同时往链表插入头结点的情况。

解决方案很简单,针对要访问的 table[i] 加上互斥锁来保护即可,因此,我们需要一个互斥锁的数组 mutex,数组大小为 NBUCKET,需要访问 table[i],就申请持有 mutex[i]

读取的时候不需要上锁,记得要先在 main 函数中初始化互斥锁。

Barrier

这个其实不难,只不过之前的 lab 让我有点害怕 moderate。。。

主要是要防止第二次 round 不会影响上一次的 round。我们保证每次,所有的线程都到达 barrier 之后才会增加一次 bstate.round

static void barrier() {
    // YOUR CODE HERE
    //
    // Block until all threads have called barrier() and
    // then increment bstate.round.
    //
    // nthread 就是我们输入的第二个参数
    pthread_mutex_lock(&bstate.barrier_mutex);
    ++bstate.nthread;
    if (bstate.nthread == nthread) {
        bstate.round += 1;
        bstate.nthread = 0;
        pthread_cond_broadcast(&bstate.barrier_cond);
    } else {
        pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex);
    }
    pthread_mutex_unlock(&bstate.barrier_mutex);
}

其实一开始因为想着条件变量总会配合 while 循环,因此写了两个 while 循环,两个条件变量来实现,但是按上面的单纯 if 就可以实现了。

标签:uint64,ld,thread,Xv6,a1,a0,Lab7,Multithreading,sd
From: https://www.cnblogs.com/zwyyy456/p/17573531.html

相关文章

  • Xv6 Lab6: Copy-on-Write Fork for xv6
    思路经过lab5:lazypageallocation之后,对xv6的pagefault的处理,算是有所了解了。今天这个COW实验,在2020年的课程视频中有对思路的讲解,可以先看看课程翻译,厘清一下思路。整体思路其实也不难,默认情况下,fokr会调用uvmcopy,将父进程的PP(物理页)复制一份,将这个PP的......
  • Xv6 Lab2
    系统调用Lab1主要是基于提供的系统调用接口来编写一些小工具程序,而Lab2则是要我们自己实现系统调用,并提供系统调用的接口。以本次Lab要我们实现的trace调用为例,说明一下系统调用的流程:在user/trace.c的第$15$行,调用了属于systemcall的trace函数,当前执行makeq......
  • Xv6 Lab4
    RISC-VassemblyWhichregisterscontainargumentstofunctions?Forexample,whichregisterholds13inmain'scalltoprintf?a2寄存器,函数调用时,参数从左到右会依次保存在a0,a1,a2,a3寄存器,似乎是一直到寄存器a7的。Whereisthecalltofunctionfinthe......
  • 【cs50】lab7 & problem set7
    (1)lab7songssqlite3songs.db1)listthenamesofallsongsinthedatabaseSELECTnameFROMsongs;2)listnamesofallsongsinincreasingorderoftempoSELECTnameFROMsongsORDERBYtempo;3) listthenamesofthetop5longests......
  • Xv6 Lab2
    系统调用Lab1主要是基于提供的系统调用接口来编写一些小工具程序,而Lab2则是要我们自己实现系统调用,并提供系统调用的接口。以本次Lab要我们实现的trace调用为例,说明一下系统调用的流程:在user/trace.c的第$15$行,调用了属于systemcall的trace函数,当前执行makeq......
  • Xv6 操作系统组织架构
    进程概述64位的RISC-V的VAS是39位的,即VA只有39位,而Xv6则只有38位,最大虚拟地址为#defineMAXVA0x3fffffffff。VAS的顶端,即最高位存放了两个page,一个是用于trampoline,一个用于mappingtheprocess'strapframe。Xv6使用这两个page来切换到内核以及返回。......
  • Python多线程(multithreading)
    1.threading模块Python3线程中常用的两个模块为:_thread,threading(推荐使用).thread模块已被废弃,为了兼容性,Python3将thread重命名为_thread,即通过标准库_thread和threading提供对线程的支持。_thread提供了低级别的、原始的线程以及一个简单的锁,它相比于threading模块的功能还......
  • 2020-07-30-python-multithreading&multiprocessing
    注:参考Python多线程多进程那些事儿看这篇就够了~~进程、线程进程和线程简单举例:对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程。有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要......
  • xv6页表
    一级页表地址64bit。虚拟地址使用low39位,物理地址使用low56位。虚拟地址的low39中,高27位是index,用来索引页表中的具体"一行"页表项。一个页表项在物理内存中是4096Byte,offset用来索引具体一个Byte。物理地址的low56中,高44位是物理页号(PPN),低12位等同于虚拟地址中的offset的1......
  • 《操作系统原型--xv6分析与实验》第一章:qemu启动xv6问题记录
    最近在学习《操作系统原型--xv6分析与实验》,第一章安装qemu和启动xv6就遇到很多障碍,特此记录一下解决办法。版本信息系统:Ubuntu22.04.1LTSxv6:rev9qemu:6.2gcc:11.2.0操作步骤ubuntu勾选了完整安装,默认自带gcc、make等构建工具。首先将用到的xv6下载下来解压,我下载的是re......