输入输出系统

news2025/4/6 17:44:57

文章目录

  • 前言
  • 前置知识
  • 实验操作
    • 实验一
    • 实验二
    • 实验三
    • 实验四
    • 实验五

前言

博客记录《操作系统真象还原》第十章实验的操作~

实验环境:ubuntu18.04+VMware , Bochs下载安装

实验内容:

  1. 添加关中断的方式保证原子性。
  2. 用锁实现终端输出。
  3. 从键盘获取输入。
  4. 实现键盘驱动软件。
  5. 添加键盘输入缓冲区。

前置知识

同步机制-锁

术语简介

  • 公共资源: 可以是公共内存、公共文件、公共硬件等,是被所有任务共享的一套资源。

  • 临界区: 访问公共资源的代码区域,临界区的代码只允许一个线程访问。强调!临界区是指程序中那些访问公共资源的指令代码,即临界区是指令。

  • 互斥:任意时刻访问公共资源只允许一个线程访问,即任意时刻访问公共资源的临界区代码中只允许被一个线程所执行。

  • 竞争条件:竞争条件指多个线程或者进程在读写一个共享数据时,结果依赖于它们执行的相对时间的情形。

【✔总结】

多线程访问公共资源时出问题的原因是产生了竞争条件,也就是多个任务同时出现在自己的临界区。为避免产生竞争条件,必须保证任意时刻只能有一个任务处于临界区。因此,只要保证各线程自己临界区中的所有代码都是原子操作,即临界区中的指令要么一条不做,要么一气呵成全部执行完,执行期间绝对不能被换下处理器。

信号量

信号量是锁的具体实现方式。

信号量是个 0 以上的整数值。当为 0 时表示已无可用信号,大于 0 表示可用的信号量的数量。

信号量就是个计数器, OS 用 P、V 操作来表示信号量的减、增。

  • P:Probern,表示减少。
  • V:Verhogen,表示增加。

V 操作包含两个微操作:

  1. 将信号量加一。
  2. 唤醒在此信号量上等待的线程。

P 操作包含三个微操作:

  1. 判断信号量是否大于0。
  2. 若信号量大于 0,则将信号量减 1。
  3. 若信号量等于 0,当前线程将自己阻塞,以在信号量上等待。

信号量的初值代表的是信号资源的剩余量,若初值为 1,则它的取值只能是 0 和 1,这便是二元信号量。

我们可以让线程通过锁进入临界区,可以借此保证只有一个线程可以进入临界区,从而做到互斥。

流程如下:

  • 在二元信号量中,P 操作就是获取锁,V 操作就是释放锁。

  • 线程 A 进入临界区前先通过 P 操作得到锁,此时信号量为 0。

  • 后续线程 B 再进入临界区也需要先通过 P 操作得到锁,由于此时信号量为 0,线程 B 便会阻塞到此信号量上,即该线程进入休眠状态。

  • 当线程 A 从临界区出来后执行 V 操作释放锁,此时信号量重新变回 1,之后线程 A 将线程 B 唤醒。

【补充】阻塞是主动的,唤醒是被动的。

键盘输入原理

键盘的内部有个叫作键盘编码器的芯片(通常是Intel 8048 或兼容芯片)。该芯片的作用是告诉键盘控制器(在主板上)哪个键被操作了。

键盘控制器的作用是接收来自键盘编码器的按键信息,将其解码后保存,然后向中断代理发中断,之后处理器执行相应的中断处理程序读入 8042 处理保存过的按键信息。

在这里插入图片描述

环形缓冲输入区

实验操作

实验一

接着这篇博客 实现内核线程

本实验 通过修改 mian.c 文件添加关中断的方式保证原子性。

#include "../lib/kernel/print.h"
#include "init.h"
#include "../thread/thread.h"
#include "../kernel/interrupt.h"

void k_thread_a(void*);
void k_thread_b(void*);
int main(void) {
   put_str("I am kernel\n");
   init_all();

   thread_start("k_thread_a", 31, k_thread_a, "argA ");
   thread_start("k_thread_b", 8, k_thread_b, "argB ");

   intr_enable();	// 打开中断,使时钟中断起作用

   while(1) {
    	 intr_disable();	 // 关中断
	 put_str("Main ");
       	 intr_enable();	 // 开中断
   };
   return 0;
}

/* 在线程中运行的函数 */
void k_thread_a(void* arg) {     
/* 用void*来通用表示参数,被调用的函数知道自己需要什么类型的参数,自己转换再用 */
   char* para = arg;
   while(1) {
      intr_disable();         // 关中断
      put_str(para);
      intr_enable();  // 开中断
   }
}

/* 在线程中运行的函数 */
void k_thread_b(void* arg) {     
/* 用void*来通用表示参数,被调用的函数知道自己需要什么类型的参数,自己转换再用 */
   char* para = arg;
   while(1) {
      intr_disable();         // 关中断
      put_str(para);
      intr_enable();  // 开中断
   }
}

在这里插入图片描述

实验二

修改 thread.c , thread.h。

新建 sync.c , sync.h 实现同步信号机制和锁。

新建 console.c,console.h 对锁操作进行封装。

修改init.c以及main.c

makefile文件

BUILD_DIR = ./build
ENTRY_POINT = 0xc0001500
AS = nasm
CC = gcc
LD = ld
LIB = -I lib/ -I lib/kernel/ -I lib/user/ -I kernel/ -I device/ 
ASFLAGS = -f elf
CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS =  -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
      $(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/switch.o \
      $(BUILD_DIR)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
      $(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o \
      $(BUILD_DIR)/sync.o $(BUILD_DIR)/console.o
      
##############     c代码编译     ###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
        lib/stdint.h kernel/init.h lib/string.h kernel/memory.h \
        thread/thread.h kernel/interrupt.h device/console.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \
        lib/stdint.h kernel/interrupt.h device/timer.h kernel/memory.h \
        thread/thread.h device/console.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \
        lib/stdint.h kernel/global.h lib/kernel/io.h lib/kernel/print.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/io.h lib/kernel/print.h \
        kernel/interrupt.h thread/thread.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h \
        lib/kernel/print.h lib/stdint.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/string.o: lib/string.c lib/string.h \
	kernel/debug.h kernel/global.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/memory.o: kernel/memory.c kernel/memory.h \
	lib/stdint.h lib/kernel/bitmap.h kernel/debug.h lib/string.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h kernel/global.h \
	lib/string.h kernel/interrupt.h lib/kernel/print.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/thread.o: thread/thread.c thread/thread.h \
	lib/stdint.h lib/string.h kernel/global.h kernel/memory.h \
	kernel/debug.h kernel/interrupt.h lib/kernel/print.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/list.o: lib/kernel/list.c lib/kernel/list.h \
	kernel/interrupt.h lib/stdint.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/sync.o: thread/sync.c thread/sync.h \
	lib/stdint.h thread/thread.h kernel/debug.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/console.o: device/console.c device/console.h \
	lib/kernel/print.h thread/sync.h
	$(CC) $(CFLAGS) $< -o $@
	
##############    汇编代码编译    ###############
$(BUILD_DIR)/kernel.o: kernel/kernel.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/print.o: lib/kernel/print.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/switch.o: thread/switch.S
	$(AS) $(ASFLAGS) $< -o $@

##############    链接所有目标文件    #############
$(BUILD_DIR)/kernel.bin: $(OBJS)
	$(LD) $(LDFLAGS) $^ -o $@

.PHONY : mk_dir hd clean all

mk_dir:
	if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi

hd:
	dd if=$(BUILD_DIR)/kernel.bin \
           of=/home/cooiboi/bochs/boot/hd60M.img \
           bs=512 count=200 seek=9 conv=notrunc

clean:
	cd $(BUILD_DIR) && rm -f  ./*

build: $(BUILD_DIR)/kernel.bin

all: mk_dir build hd

make all

这里需要根据make all的报错修改导入库的路径(使用相对路径)

然后启动Bochs

sudo bin/bochs -f boot/bochsrc.disk

在这里插入图片描述

实验三

修改kernel.S,interrupt.c

编写keyboard.c,keyboard.h

修改main.c,init.c(注意:修改thread.h库 <…/thread/thread.h>)

makefile 文件

BUILD_DIR = ./build
ENTRY_POINT = 0xc0001500
AS = nasm
CC = gcc
LD = ld
LIB = -I lib/ -I lib/kernel/ -I lib/user/ -I kernel/ -I device/ 
ASFLAGS = -f elf
CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS =  -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
      $(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/switch.o \
      $(BUILD_DIR)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
      $(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o \
      $(BUILD_DIR)/sync.o $(BUILD_DIR)/console.o $(BUILD_DIR)/keyboard.o
      
##############     c代码编译     ###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
        lib/stdint.h kernel/init.h lib/string.h kernel/memory.h \
        thread/thread.h kernel/interrupt.h device/console.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \
        lib/stdint.h kernel/interrupt.h device/timer.h kernel/memory.h \
        thread/thread.h device/console.h device/keyboard.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \
        lib/stdint.h kernel/global.h lib/kernel/io.h lib/kernel/print.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/io.h lib/kernel/print.h \
        kernel/interrupt.h thread/thread.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h \
        lib/kernel/print.h lib/stdint.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/string.o: lib/string.c lib/string.h \
	kernel/debug.h kernel/global.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/memory.o: kernel/memory.c kernel/memory.h \
	lib/stdint.h lib/kernel/bitmap.h kernel/debug.h lib/string.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h kernel/global.h \
	lib/string.h kernel/interrupt.h lib/kernel/print.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/thread.o: thread/thread.c thread/thread.h \
	lib/stdint.h lib/string.h kernel/global.h kernel/memory.h \
	kernel/debug.h kernel/interrupt.h lib/kernel/print.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/list.o: lib/kernel/list.c lib/kernel/list.h \
	kernel/interrupt.h lib/stdint.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/sync.o: thread/sync.c thread/sync.h \
	lib/stdint.h thread/thread.h kernel/debug.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/console.o: device/console.c device/console.h \
	lib/kernel/print.h thread/sync.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/keyboard.o: device/keyboard.c device/keyboard.h \
	lib/kernel/print.h lib/kernel/io.h kernel/interrupt.h \
	kernel/global.h
	$(CC) $(CFLAGS) $< -o $@
	
##############    汇编代码编译    ###############
$(BUILD_DIR)/kernel.o: kernel/kernel.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/print.o: lib/kernel/print.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/switch.o: thread/switch.S
	$(AS) $(ASFLAGS) $< -o $@

##############    链接所有目标文件    #############
$(BUILD_DIR)/kernel.bin: $(OBJS)
	$(LD) $(LDFLAGS) $^ -o $@

.PHONY : mk_dir hd clean all

mk_dir:
	if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi

hd:
	dd if=$(BUILD_DIR)/kernel.bin \
           of=/home/cooiboi/bochs/boot/hd60M.img \
           bs=512 count=200 seek=9 conv=notrunc

clean:
	cd $(BUILD_DIR) && rm -f  ./*

build: $(BUILD_DIR)/kernel.bin

all: mk_dir build hd

make all
sudo bin/bochs -f boot/bochsrc.disk

在这里插入图片描述

实验四

修改 keyboard.c

在这里插入图片描述

实验五

添加ioqueue.h,ioqueue.c(环形缓冲区及其方法定义)

修改keyboard.c

makefile

BUILD_DIR = ./build
ENTRY_POINT = 0xc0001500
AS = nasm
CC = gcc
LD = ld
LIB = -I lib/ -I lib/kernel/ -I lib/user/ -I kernel/ -I device/ 
ASFLAGS = -f elf
CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS =  -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
      $(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/switch.o \
      $(BUILD_DIR)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
      $(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o \
      $(BUILD_DIR)/sync.o $(BUILD_DIR)/console.o $(BUILD_DIR)/keyboard.o \
      $(BUILD_DIR)/ioqueue.o
##############     c代码编译     ###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
        lib/stdint.h kernel/init.h lib/string.h kernel/memory.h \
        thread/thread.h kernel/interrupt.h device/console.h \
        device/keyboard.h device/ioqueue.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \
        lib/stdint.h kernel/interrupt.h device/timer.h kernel/memory.h \
        thread/thread.h device/console.h device/keyboard.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \
        lib/stdint.h kernel/global.h lib/kernel/io.h lib/kernel/print.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/io.h lib/kernel/print.h \
        kernel/interrupt.h thread/thread.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h \
        lib/kernel/print.h lib/stdint.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/string.o: lib/string.c lib/string.h \
	kernel/debug.h kernel/global.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/memory.o: kernel/memory.c kernel/memory.h \
	lib/stdint.h lib/kernel/bitmap.h kernel/debug.h lib/string.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h kernel/global.h \
	lib/string.h kernel/interrupt.h lib/kernel/print.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/thread.o: thread/thread.c thread/thread.h \
	lib/stdint.h lib/string.h kernel/global.h kernel/memory.h \
	kernel/debug.h kernel/interrupt.h lib/kernel/print.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/list.o: lib/kernel/list.c lib/kernel/list.h \
	kernel/interrupt.h lib/stdint.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/sync.o: thread/sync.c thread/sync.h \
	lib/stdint.h thread/thread.h kernel/debug.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/console.o: device/console.c device/console.h \
	lib/kernel/print.h thread/sync.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/keyboard.o: device/keyboard.c device/keyboard.h \
	lib/kernel/print.h lib/kernel/io.h kernel/interrupt.h \
	kernel/global.h lib/stdint.h device/ioqueue.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/ioqueue.o: device/ioqueue.c device/ioqueue.h \
	kernel/interrupt.h kernel/global.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
##############    汇编代码编译    ###############
$(BUILD_DIR)/kernel.o: kernel/kernel.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/print.o: lib/kernel/print.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/switch.o: thread/switch.S
	$(AS) $(ASFLAGS) $< -o $@

##############    链接所有目标文件    #############
$(BUILD_DIR)/kernel.bin: $(OBJS)
	$(LD) $(LDFLAGS) $^ -o $@

.PHONY : mk_dir hd clean all

mk_dir:
	if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi

hd:
	dd if=$(BUILD_DIR)/kernel.bin \
           of=/home/cooiboi/bochs/boot/hd60M.img \
           bs=512 count=200 seek=9 conv=notrunc

clean:
	cd $(BUILD_DIR) && rm -f  ./*

build: $(BUILD_DIR)/kernel.bin

all: mk_dir build hd

在这里插入图片描述
参考资料

  • 《操作系统真象还原》
  • 《操作系统真象还原》第十章 ---- 线程打印尚未成功 仍需此章锁机制完善努力 在前往最终章的路上激流勇进
  • 《操作系统-真象还原》10. 输入输出系统

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

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

相关文章

Docker中的网络模式

使用命令docker inspect 容器id/name能看到容器的ip地址&#xff0c;使用主机和其他容器ping这个地址发现都是可以ping通的&#xff0c;但是使用本地局域网内的其他机器是无法ping通的。 Docker的默认网络模式可以分为&#xff1a;Host 模式、Bridge 模式或者 None 模式。然后来…

word中导入zotero的参考文献

平时使用Zotero管理文献&#xff0c;使用Word写完论文后想用Zotero导入参考文献&#xff0c;也方便修改参考文献格式。 Zotero 打开Zotero找到编辑-首选项 打开首选项&#xff0c;下载国标格式&#xff0c;引用-获取更多样式-搜索框&#xff1a;China Word Word中打开写的…

APSIM练习 :机会种植

该练习是设置一个播种规则&#xff0c;根据条件情况&#xff0c;自动取使用哪种作物进行轮作。 在之前的练习中&#xff0c;我们每年都会重置起始条件。我们不打算在本练习中进行此重置。相反&#xff0c;我们将研究如何根据这些不同的起始条件改变播种的内容&#xff1b;具体…

Docker简介以及安装

官方链接&#xff1a; Docker官网 Docker仓库地址 1、基本要求 docker要求Linux内核系统64位&#xff0c;内核在3.8以上 cat /etc/redhat-release uname -r 2、三要素 2.1、镜像 2.2、容器 2.3、仓库 镜像存放的地方,有点类似Maven仓库 3、安装步骤 官网指导&#xff…

最大比例(数论 最大公约数 辗转相减法)[第七届蓝桥杯省赛C++A/B组]

题目如下&#xff1a; 题解 or 思路&#xff1a; 假设题中所给的数据为 b1,b2,b3,⋅⋅⋅,bnb_1,b_2,b_3,⋅⋅⋅,b_nb1​,b2​,b3​,⋅⋅⋅,bn​,分别用第一项之后的项除以第一项&#xff0c;得到&#xff1a;b2b1,b3b1,⋅⋅⋅&#xff0c;bnb1\frac{b2}{b1},\frac{b3}{b1},⋅⋅…

【Axure教程】自动识别文件类型的上传列表

文件上传是系统中很常用的功能&#xff0c;所以今天作者就教大家在Axure中如何利用中继器&#xff0c;制作一个能自动识别常用的文件类型的上传列表。 一、效果展示 1、点击上传按钮&#xff0c;可以选择本地的文件进行上传 2、选择文件后&#xff0c;在上传列表中新增该文件…

学生用台灯应该选什么样的?看这一篇就够了~

学生在选购一款台灯时&#xff0c;最重要的考虑因素应该是什么&#xff1f;最重要是这款台灯是否真正护眼&#xff0c;价格和外观是次要的&#xff0c;可以根据预算、用途、家居风格来抉择&#xff0c;而是否护眼这一标准需要我们通过衡量台灯的光线指标来判断了。光线指标的五…

ORB-SLAM2 --- LoopClosing::SearchAndFuse函数

目录 1.函数作用 2. code及解析 3. ORBmatcher::Fuse函数解析&#xff08;闭环调用版&#xff09; 1.函数作用 将闭环相连关键帧组mvpLoopMapPoints 投影到当前关键帧组中&#xff0c;进行匹配&#xff0c;新增或替换当前关键帧组中KF的地图点。 2. code及解析 /*** brief 将…

第21章 随机游走

第21章 随机游走 随机游走的建模场景是某个对象按照随机选择的方向行走一个步数序列。 21.1赌徒破产 假设一个赌徒一开始有n美元赌注&#xff0c;他要进行一系列1美元投注。如果他赢得一局&#xff0c;则拿回他的赌注外加1美元。如果他输了&#xff0c;那么他将失去1美元。 …

MySQL中InnoDB的事务隔离

文章目录前言一、事务介绍二、事务的四大特性三、事务的隔离性四、事务隔离的实现前言 我们在实际开发中&#xff0c;执行某个业务&#xff0c;肯定不是简单的操作某一句SQL语句&#xff0c;而是多条SQL语句。那么这多条SQL语句必须是全部成功执行&#xff0c;或者全部失败。才…

[L1 - 10分合集]吃鱼还是吃肉

L1-063 吃鱼还是吃肉 分数 10 作者 陈越 单位 浙江大学 题目&#xff1a; 国家给出了 8 岁男宝宝的标准身高为 130 厘米、标准体重为 27 公斤&#xff1b;8 岁女宝宝的标准身高为 129 厘米、标准体重为 25 公斤。 现在你要根据小宝宝的身高体重&#xff0c;给出补充营养的建议…

最近发现关于计算机网络的1个秘密

最近闲着没啥事翻开之前谢希仁老师第7版的《计算机网络》这本书,结果发现了1个惊天的秘密。 首先是互联网与互连网的区别,一般我们常说的互联网是Internet,是指因特网,其起源于阿帕网。或许很多读者看到这里就觉得有什么秘密可言,不都是常识了吗?看你大惊小怪的。 我们不妨看看…

spring cloud、gradle、父子项目、微服务框架搭建---rabbitMQ延时队列(七)

总目录 https://preparedata.blog.csdn.net/article/details/120062997 文章目录总目录一、rabbit延时插件下载二、rabbit插件安装三、项目中配置延时队列四、定义消息通道五、生成消息六、监听消息&#xff0c;进行消费延时队列的配置是对上片文章的延伸扩展 https://prepare…

paddledetection推理代码结构

https://github.com/PaddlePaddle/PaddleDetection/blob/release%2F2.5/deploy/pipeline/README.mdhttps://github.com/PaddlePaddle/PaddleDetection/blob/release%2F2.5/deploy/pipeline/README.md GitHub - leeguandong/Xiaobao: videoclip&#xff0c;视频剪辑应用videocl…

Go 1.19.3 error原理简析

Go error是一个很痛的话题(真心难用) 标准库 error 的定义 // The error built-in interface type is the conventional interface for // representing an error condition, with the nil value representing no error. type error interface {Error() string }error 是一个…

windows10安装wireshark

win10安装wireshark并使用windows10安装wireshark下载WIRESHARK下载Win10Pcapwindows10安装wireshark 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解一下Markdown的基本语法知…

javaEE 初阶 — JUC(java.util.concurrent) 的常见类

文章目录1. Callable 接口1.1 Callable 的用法2. ReentrantLock2.1 ReentrantLock 的缺陷2.1 ReentrantLock 的优势3. 原子类4. 信号量 Semaphore5. CountDownLatch6. 相关面试题1. Callable 接口 类似于 Runnable 一样。 Runnable 用来描述一个任务&#xff0c;描述的任务没有…

【Spring源码】21. 关于循环依赖的N个问题

完成了applyMergedBeanDefinitionPostProcessors()方法&#xff0c;后面有一段关于判断Bean是否需要提前曝光的逻辑&#xff08;如下图红框框中部分&#xff09;在这段逻辑中涉及到了著名的循环依赖&#xff0c;提到循环依赖基本必讲三级缓存&#xff0c;好吧&#xff0c;这篇就…

CANOpen中SDO和PDO的COB-ID理解

CAN 总线是一种串行通信协议&#xff0c;具有较高的通信速率的和较强的抗干扰能力&#xff0c;可以作为现场总线应用于电磁噪声较大的场合。由于 CAN 总线本身只定义ISO/OSI 模型中的第一层&#xff08;物理层&#xff09;和第二层&#xff08;数据链路层&#xff09;&#xf…

(8)go-micro微服务Mysql配置

文章目录一 gorm介绍二 gorm安装1.1 下载依赖1.2 使用MySQL驱动三 CURD操作1. 查询1.1 单行查询1.2 多行查询2. 插入数据3. 更新数据4. 删除数据四 初始化连接五 使用六 最后一 gorm介绍 Go语言中的database/sql包提供了保证SQL或类SQL数据库的泛用接口&#xff0c;并不提供具…