8.Lab Sevent —— Multithreading

news2024/11/15 1:46:41

首先切换到thread分支

git checkout thread
make clean

Uthread:switch between threads

为用户级线程系统设计上下文切换机制

xv6中已经放了两个文件:

  • user/uthread.cuser/uthread_switch.S

  • 以及一个规则:运行在Makefile中以构建uthread程序。

  • uthread.c包含大多数用户级线程包,以及三个简单测试线程的代码。

实现用户级线程切换,比起xv6中实现内核级线程,这个更简单一些,因为用户级线程不需要设计用户栈和内核栈,用户页表和内核页表切换等等

1.定义存储上下文的结构体tcontext(kernel/proc.h)同时修改uthread.c(user/uthread.c)中的thread结构体

2.类似按照kernel/swtch.S,修改user/uthread_switch.S中写入如下代码

3.更改thread_scheduler(user/uthread.c),进行线程的轮询并找到下一个需要执行的切换

其中thread_yield函数是默认提供好的

Using threads

在文件notxv6/ph.c中包含一个简单的哈希表,如果单个线程使用,该哈希表是正确,但是多个线程使用时,该哈希表不正确,可以在主目录中输入如下命令:

make ph
./ph 1

结果如下:

ph的参数指定在哈希表上执行put和get的线程数,可以看到没有missing,100000 puts 也对应 10000 gets

但是当使用多个线程的时候,例如2,结果如下:

$ ./ph 2
100000 puts, 4.385 seconds, 23044 puts/second
1: 16579 keys missing
0: 16579 keys missing
200000 gets, 8.422 seconds, 23597 gets/second

可以看到丢失了不少,但数字确实貌似是二倍的样子,pu运行两个基准程序,通过put()将许多键添加到哈希表,并以秒为单位打印puts的速率,然后它使用get()从哈希表中获取键,打印由于puts而应该在哈希表中单丢失的键的数量。然而,16579 keys missing的两行代表丢失了大量的键

所以这里需要使用多进程必须进行上锁

设定了五个散列桶,根据键除以5的余数来确定插入到哪个散列桶中,插入的方式是头插法

造成数据丢失原因:

  • 假设现在有两个线程T1和T2,两个线程都走到put函数,且假设两个线程中 key%NBUCKET相同

  • 两个线程同时调用insert(key, value, &table[i], table[i]),第一个参数是传需要插入的内存地址,第二个参数是需要插入的某块内存(插入到该内存之前)insert是通过头插法实现的。如果先insert的线程还未返回另一个线程就开始insert,那么前面的数据会被覆盖

1.在notxv6/ph.c为每个散列桶定义一个锁,将五个锁放在一个数组中,并进行初始化

2.在put函数中对insert函数上锁(get不需要,因为不会修改只是读)

加锁后测试:


 

Barrier

实现一个内存屏障(Barrier):

应用程序中的某个点,所有参与的线程都必须在此点上等待,知道其他所有参与的线程也到达该点

在notxv6/barrier.c中包含一个残缺的屏障实现

$ make barrier
$ ./barrier 2
barrier: notxv6/barrier.c:42: thread: Assertion `i == t' failed.

2 指明了在屏障上同步的线程数,每个线程执行一个循环,每次循环迭代中,线程都会调用barrier(),然后以随机微秒数休眠,如果一个线程在另一个线程到达屏障之前离开屏障将触发断言。希望达到的效果是每个线程在barrier()中阻塞,直到nthreads的所有线程都调用了barrier()

看一下notxv6/barrier.c中的代码逻辑(已经完成了barrier函数的实现)

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>

static int nthread = 1;
static int round = 0;

// 互斥锁,条件变量,到达屏障的线程数、轮数
struct barrier {
  pthread_mutex_t barrier_mutex;
  pthread_cond_t barrier_cond;
  int nthread;      // Number of threads that have reached this round of the barrier
  int round;     // Barrier round
} bstate;

//初始化屏障
static void
barrier_init(void)
{
  assert(pthread_mutex_init(&bstate.barrier_mutex, NULL) == 0);
  assert(pthread_cond_init(&bstate.barrier_cond, NULL) == 0);
  bstate.nthread = 0;
}

//屏障函数,已经实现
static void 
barrier()
{
  // YOUR CODE HERE
  //
  // Block until all threads have called barrier() and
  // then increment bstate.round.
  //
  //申请锁,互斥操作
  pthread_mutex_lock(&bstate.barrier_mutex);
  // judge whether all threads reach the barrier
  if(++bstate.nthread != nthread)  {    // not all threads reach    
    pthread_cond_wait(&bstate.barrier_cond,&bstate.barrier_mutex);  // wait other threads
  } else {  // all threads reach
    bstate.nthread = 0; // reset nthread
    ++bstate.round; // increase round
    pthread_cond_broadcast(&bstate.barrier_cond);   // wake up all sleeping threads
  }
  pthread_mutex_unlock(&bstate.barrier_mutex);

}

//每个线程执行的函数
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;
}

int
main(int argc, char *argv[])
{
  pthread_t *tha;
  void *value;
  long i;
  double t1, t0;

  if (argc < 2) {
    fprintf(stderr, "%s: %s nthread\n", argv[0], argv[0]);
    exit(-1);
  }
  //参数指定线程数量
  nthread = atoi(argv[1]);
  tha = malloc(sizeof(pthread_t) * nthread);
  // srandom 是 C 标准库中的一个函数,用于设置伪随机数生成器(PRNG)的起始种子 -- 输出只是伪随机而不是真正的随机数
  srandom(0);

  barrier_init();

  //创建n个线程执行
  for(i = 0; i < nthread; i++) {
    assert(pthread_create(&tha[i], NULL, thread, (void *) i) == 0);
  }
  for(i = 0; i < nthread; i++) {
    assert(pthread_join(tha[i], &value) == 0);
  }
  printf("OK; passed\n");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2143262.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux:用户账号管理和组账号管理

用户账号管理 账号控制总述 用户账户 作用: 1.可以登陆操作系统 2.不同的用户具备不同的权限 唯一标识&#xff1a;UID&#xff08;编号从0开始的编号&#xff0c;默认最大60000&#xff09;zhangsan(UID 1200) 管理员root的UID&#xff1a;永远为0 系统用户&#xff08;为程…

django学习入门系列之第十点《A 案例: 员工管理系统9》

文章目录 12 管理员操作12.1 添加的界面集成12.2更改样式12.3验证密码 往期回顾 12 管理员操作 12.1 添加的界面集成 因为添加界面基本不用怎么改&#xff0c;所以可以直接集成进去 需要再次改动的地方 这样的话相当于直接在视图界面上直接传就行了&#xff0c;来提高复用率…

二十种编程语言庆祝中秋节

二十种编程语言庆祝中秋节 文章目录 二十种编程语言庆祝中秋节中秋快乐&#xff01;家人们 &#x1f973;一 Python二 C三 C四 Java五 C#六 Perl七 Go八 Asp九 PHP十 JavaScript十一 JavaScript HTML十二 Visual Basic十三 早期 VB十四 Visual C十五 Delphi十六 Shell十七 Cobo…

鸿蒙开发之ArkTS 界面篇 一

建好一个工程后&#xff0c;右侧可以预览&#xff0c;看到效果&#xff0c;效率十分可以&#xff0c;如图: State message: string 鸿蒙开发入门篇; 这个字符串改成什么&#xff0c;右侧就显示什么 Entry是类装饰器&#xff0c;可以简单的理解为程序入口的必须的装饰器&…

25届校招IQCAT思维能力自适应测验智鼎测评指南:题库获取、刷题策略与真题解析!

IQCAT思维能力自适应测验考试内容介绍 IOCAT思维能力自适应测验基于二因素智力理论&#xff0c;通过考察作答者的一般认知能力&#xff0c;预测其学习新知识、新技能以及理解、解决问题时的工作表现。IQCAT使用自适应测验技术&#xff0c;根据作答者的作答情况&#xff0c;从题…

shell脚本语法

shell脚本的变量 系统变量 系统变量是操作系统用来存储配置信息的变量&#xff0c;它们可以控制操作系统的行为和程序的运行环境。系统变量的种类和内容取决于操作系统的类型和版本。以下是一些常见的系统变量类别和它们可能包含的内容&#xff1a; 环境变量&#xff1a;这些…

OpenCV calcHist()函数及其用法详解

OpenCV calcHist()函数原型共有三个&#xff0c;如下&#xff1a; 该函数计算一个或多个数组的直方图。用于递增直方图箱的元组的元素取自同一位置的相应输入数组。 函数参数&#xff1a; images 源&#xff08;图像&#xff09;数组。它们都应具有相同的深度、CV_8U、CV_16U…

YOLOv8改进 - 注意力篇 - 引入CBAM注意力机制

一、本文介绍 作为入门性第一篇&#xff0c;这里介绍了CBAM注意力在YOLOv8中的使用。包含CBAM原理分析&#xff0c;CBAM的代码、CBAM的使用方法、以及添加以后的yaml文件及运行记录。 二、CBAM原理分析 CBAM官方论文地址&#xff1a;CBAM论文 CBAM的pytorch版代码&#xff…

Gateway网关的实现

API网关 网关路由必须支持负载均衡&#xff0c;服务列表是从注册中心拉取的客户端发出请求的URL指向的是网关&#xff0c;URL还必须要包含目标信息网关收到URL&#xff0c;通过一定的规则&#xff0c;要能识别出交给哪个实例去处理网关有能力对请求响应进行修改 引入依赖包 …

图论算法(DFS/BFS/拓扑排序/最短路/最小生成树/二分图/基环树/欧拉路径)

DFS 基础 BFS 基础 Leetcode 815. 公交路线 思路&#xff1a; class Solution { public:int numBusesToDestination(vector<vector<int>>& routes, int source, int target) {// 记录经过车站x的公交车编号 hashunordered_map<int, vector<int>> …

frp内网穿透功能使用教程

frp 是一款高性能的反向代理应用&#xff0c;专注于内网穿透。它支持多种协议&#xff0c;包括 TCP、UDP、HTTP、HTTPS 等&#xff0c;并且具备 P2P 通信功能。使用 frp&#xff0c;您可以安全、便捷地将内网服务暴露到公网&#xff0c;通过拥有公网 IP 的节点进行中转。 文档地…

Python3网络爬虫开发实战(15)Scrapy 框架的使用(第一版)

文章目录 一、Scrapy 框架介绍1.1 数据流1.2 项目结构1.3 Scrapy 入门 二、Selector 解析器2.1 XPath 和 CSS 选择器2.2 信息提取2.3 正则提取 三、Spider 的使用3.1 Spider 运行流程3.2 Spider 类分析3.3 Request3.4 Response 四、Download Middleware 的使用4.1 process_requ…

55.【C语言】字符函数和字符串函数(strstr函数)

11.strstr函数 *简单使用 strstr: string string cplusplus的介绍 点我跳转 翻译: 函数 strstr const char * strstr ( const char * str1, const char * str2 ); 或另一个版本char * strstr ( char * str1, const char * str2 ); 寻找子字符串 返回指向第一次出现在字…

PostMan使用变量

环境变量 使用场景 当测试过程中&#xff0c;我们需要对开发环境、测试环境、生产环境进行测试 不同的环境对应着不同的服务器&#xff0c;那么这个时候我们就可以使用环境变量来区分它们 避免切换测试环境后&#xff0c;需要大量的更改接口的url地址 全局变量 使用场景 当…

chapter2-站点首页功能实现

1. 导航功能实现 导航数据的存储&#xff0c;必须要找出导航数据的结构&#xff0c;也就是有哪些属性&#xff1f; 导航位置、导航名称、导航链接、导航序号、是否显示、是否外链、添加时间、更新时间、是否删除 E-R图&#xff0c;如下&#xff1a; 1.1 创建模型 home/model…

Ardupilot开源飞控之VTOL之旅:且败且战

Ardupilot开源飞控之VTOL之旅&#xff1a;且败且战 1. 源由2. 希望3. 打印件3.1 Back_cover_AKK_Race_Ranger_VTX_SMA3.2 CRSF-Ant_mount_TPU3.3 H743_mount 4. 其他问题5. 总结6. 参考资料 1. 源由 折腾了这么久&#xff0c;可是VTOL就是一直没有装起来&#xff0c;主要问题还…

vs2022快捷键异常解决办法

安装了新版本的vs2022&#xff0c;安装成功后&#xff0c;发现快捷键发生异常&#xff0c;之前常用的快捷键要么发生改变&#xff0c;要么无法使用&#xff0c;比如原来注释代码的快捷键是ctrlec&#xff0c;最新安装版本变成了ctrlkc&#xff0c;以前编译代码的快捷键是F6或者…

【delphi】正则判断windows完整合法文件名,包括路径

在 Delphi 中&#xff0c;可以使用正则表达式来检查 Windows 文件名称或路径是否合法。合法的文件名和路径要求符合以下几点&#xff1a; 禁止的字符&#xff1a;文件名和路径不能包含以下字符&#xff1a;<, >, :, ", /, \, |, ?, *。文件名不能以空格或点结束。…

一文讲懂Mac中的环境变量

你是否曾经因为环境变量配置不当而浪费了宝贵的开发时间?你是否好奇为什么有时候在终端输入命令会提示"command not found",而有时候又能正常运行?如果你是一名Mac用户,并且希望真正掌握环境变量的奥秘,那么这篇文章将为你揭开Mac中环境变量的神秘面纱,帮助你成为一…

BFS 解决边权为1的最短路问题

边权为1的最短路问题 最短路问题&#xff1a; 比如说从D->K&#xff0c;找出最短的那条&#xff0c;其中每条路都是有权值&#xff0c;此篇主要讲解的边权为1的最短路问题。 即边权都是一样的。 解法就是从起点开始&#xff0c;做一次BFS&#xff1a; 需要一个队列、一个…