实现内核线程

前言

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

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

实验内容:

  1. 在内核空间实现线程。
  2. 实现双向链表。
  3. 实现多线程在调度器的调度下轮流执行。

前置知识

执行流

代码运行过程中,程序计数器指向下一条指令所组成的执行轨迹称为程序的控制执行流。

执行流就是一段逻辑上独立的指令区域,是人为安排的处理单元。

执行流是独立的,它的独立性体现在每个执行流都有自己的栈、寄存器映像或内存资源等。

任何代码块都可以是执行流,只需要为其提供上下文即可(因为它是独立的)。

在任务调度器中,只有执行流才是调度单元,即处理器上运行的都是调度器给分配的执行流,只要成为执行流就能独立上处理器运行了。

线程

来看一个程序了解线程

#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
void* thread_func(void* _arg){
    
    
	unsigned int* arg = _arg;
	//cout<<"new thread: my tid is "<<*arg<<endl;
	printf("new thread: my tid is %u\n",*arg);
}
void main(){
    
    
	pthread_t new_thread_id;
	pthread_create(&new_thread_id,NULL,thread_func,&new_thread_id);
	//cout<<"main thread: my tid is "<<pthread_self()<<endl;
	printf("main thread: my tid is %u\n",pthread_self()<<pthread_self());	
	usleep(100);	
}
(base) user@ubuntu:~/Desktop/OS/MD$ gcc  test.c -o test -lpthread -Wformat=0
(base) user@ubuntu:~/Desktop/OS/MD$ ls
test  test.c
(base) user@ubuntu:~/Desktop/OS/MD$ ./test 
main thread: my tid is 1126225728
new thread: my tid is 1117751040

pthread_create原型

int pthread_create(pthread_t* restrict tidp,const pthread_attr_t* restrict_attr,void* (*start_rtn)(void*),void *restrict arg);

  • 参数__newthread用于存储新创建线程的 id。
  • 参数__attr用于指定线程的类型。这里用默认NULL。
  • 参数__start_routine 是个函数指针。确切地说是个返回值为 void*、参数为 void*的函数指针,
    用来指定线程中所调用的函数的地址,或者说是在线程中运行的函数的地址。
  • 参数__arg,它是用来配合第 3 个参数的,是给在线程中运行的函数__start_routine 的参数。

在高级语言中,线程是运行函数的另一种方式,也就是说,构建一套线程方法,让函数在此线程中被调用,然后处理器去执行这个函数,因此线程实际的功能就是相当于调用了这个函数,从而让函数执行

因此,给任何想单独上处理器的代码块准备好它所依赖的上下文环境,从而使其具备独立性,使之成为执行流,即调度单元。

进程与线程

程序程序是指静态的、存储在文件系统上、尚未运行的指令代码

进程进程是指正在运行的程序,程序必须在获得运行所需要的各类资源后才能成为进程,资源包括进程所使用的栈,使用的寄存器等。

线程进程是一种控制流集合,集合中至少包含一条执行流,执行流之间是相互独立的,但它们共享进程的所有资源,它们是处理器的执行单位,或者称为调度单位,它们就是线程。【在显示创建线程后,任务调度器就可以把它所对应的代码块从进程中分离出来,单独调度上处理器执行】

进程按照线程数量划分单线程进程和多线程进程。

区别:进程拥有整个地址空间,即是资源的所有者,而线程没有自己的地址空间,线程依赖于进程的地址空间,也就是说线程依赖于进程中的资源,因此线程被称为轻量级进程。进程=线程+资源

实验操作

实验一

新建thread文件夹,并在下面创建 thread.c 和 thread.h

root@ubuntu:/home/cooiboi/bochs# mkdir thread
root@ubuntu:/home/cooiboi/bochs/thread# vim thread.c
root@ubuntu:/home/cooiboi/bochs/thread# vim thread.h

修改 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)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
      $(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.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
	$(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
	$(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/stdint.h\
        lib/kernel/io.h lib/kernel/print.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
	$(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)/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

启动Bochs ~

在这里插入图片描述

学习资料:

线程的原理及线程和线程调度的简单实现

实验二

lib/kernel 下创建 list.c 和 list.h

root@ubuntu:/home/cooiboi/bochs/lib/kernel# vim list.c
root@ubuntu:/home/cooiboi/bochs/lib/kernel# vim list.h

实验三

参考自: 《操作系统真象还原》第九章 ---- 终进入线程动斧开刀 豁然开朗拨云见日 还需解决同步机制才能长舒气

切换线程的步骤:

1、先创建线程
2、打开中断 每个时钟中断调用中断函数 减去当前时间片
3、时间片为0 简称到期了 到期之后 调用schedule调度器 切换线程
4、schedule 把在最前面的准备队列的任务的pcb获取 把当前的放到最后
5、之后转到switch_to 保存寄存器 上下文环境 切换esp 即切换线程

修改/新建 thread.h,thread.c,interrupt.c,switch.S,timer.c,timer.h,main.c,print.S,print.h

global.h

在这里插入图片描述

init.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)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
      $(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o $(BUILD_DIR)/switch.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
	$(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
	$(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)/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

启动Bochs

sudo bin/bochs -f boot/bochsrc.disk

在这里插入图片描述


Bug:缺页,记得要初始化init.c

在这里插入图片描述

在这里插入图片描述


【注意事项】

  1. 修改文件要仔细,并不是只修改书中讲解的文件。
  2. 注意导入库文件时的相对路径。

由于知识掌握的不够,实验三调式了很久 QAQ

参考资料

猜你喜欢

转载自blog.csdn.net/weixin_42888638/article/details/128642259