Java程序员需要掌握的计算机底层知识(五):内核同步方法
内核同步机制
关于同步理论的一些基本概念
- 临界区(critical area): 访问或操作共享数据的代码段
简单理解:synchronized大括号中部分(原子性) - 竞争条件(race conditions)两个线程同时拥有临界区的执行权
- 数据不一致:data unconsistency 由竞争条件引起的数据破坏
- 同步(synchronization)避免race conditions
- 锁:锁是完成同步的手段(门锁,门后是临界区,只允许一个线程存在)
上锁解锁必须具备原子性(如果连上锁的过程都会被打断的话,就没有什么意义了) - 原子性(象原子一样不可分割的操作)
- 有序性(禁止指令重排)
- 可见性(一个线程内的修改,另一个线程可见)
互斥锁 排他锁 共享锁 分段锁
内核同步常用方法
了解一下Linux内核实现的一些同步方法,了解一些关于线程控制的理论知识,可以去印证Java层面的同步知识。
用的话要用C语言去调用。
-
原子操作 – Linux内核中提供了类似于 Java 中的 AtomicXXX 的原子操作,位于Linux内核源码的头文件
<linux/types.h>
,是从原语层面的支持,不需要实现CAS -
自旋锁 – 内核中通过汇编支持的CAS自旋锁,位于
<asm/spinlock.h>
。 -
读-写自旋 – 类似于
ReadWriteLock
,可以同时读,但只能一个写
相当于:读的时候是共享锁,写的时候是排他锁 -
信号量 – 类似于Java中的
Semaphore
(PV操作,down up操作,就是占有锁和释放锁)
是一个重量级锁,线程会进入wait,适合长时间持有的锁情况 -
读-写信号量 – downread upread downwrite upwrite
(多个写,可以分段写,比较少用)(分段锁) -
互斥体(mutex) – 特殊的信号量(二值信号量)
-
完成变量 – 特殊的信号量(A发出信号给B,B等待在完成变量上)
vfork() 在子进程结束时通过完成变量叫醒父进程 类似于(Latch)
在网络编程中有完成端口(Completion Port) -
BKL:大内核锁 Big kernel lock(早期,现在已经不用)
-
顺序锁(内核版本2.6之后新增加的): – 线程可以挂起的读写自旋锁
序列计数器(从0开始,写时增加(+1),写完释放(+1),读线程不对计数器做任何操作)
写的时候,不妨碍读线程:
如果读线程发现是偶数,说明在读的时候没有任何人改变过。
如果读线程发现是奇数,说明你读到的可能是中间状态,你可以选择继续自旋,等待值变为偶数。
读前读后序列一样,说明没有写线程打断。 -
禁止抢占 –
preempt_disable()
:我这个线程在执行过程中,不允许任何线程打断我。 -
内存屏障 – 见 volatile
汇编实现引导程序
bootloader
被写死在磁盘上固定的扇区,启动后被加载到内存张一个固定的位置。BIOS去这个位置执行第一条指令。
编写汇编码
将程序烧到软盘上,用软盘启动,模拟启动过程
; 文件名 boot.asm
org 7c00h ; BIOS读入MBR后,从固定的0x7c00h处开始执行。因此引导程序一定要放在这个位置才能执行。
; 下面部分和10h有关中断,10h中断用来显示字符
; 8086CPU 16位寄存器想用20位寻址,于是加了段寄存器。为了向后兼容,后来一直保留
mov ax, cs 下来。
mov es, ax
mov ax, msg
mov bp, ax ; ES:BP表示显示字符串的地址
mov cx, msgLen ; CX存字符长度
mov ax, 1301h ; AH=13h表示向TTY字符终端显示字符,AL=01h表示显示方式(字符串是否包含显示属性,01h表示不包含)
mov bx, 000fh ; BH=00h表示页号第0页,BL=0fh表示颜色白色
mov dl, 0 ; 表示位于第0列
int 10h ; 在上面这些固定的寄存器当中放好数据后,直接调用中断函数即可
msg: db "hello world, welcome to OS!"
msgLen: equ $ - msg ; 字符串长度
times 510 - ($ - $$) db 0 ; 填充剩余部分
dw 0aa55h ; 魔数,必须有这两个字节BIOS才确认是MBR,即主引导记录(是装有Linux系统的硬盘的第一个扇区)
编译
nasm boot.asm -o boot.bin
制作启动软盘
-
dd if=/dev/zero of=floppy.img bs=1474560 count=1
生成空白软盘镜像 -
dd if=boot.bin of=myos.img bs=512 count=1
制作包含主引导记录boot.bin的启动镜像文件 -
dd if=floppy.img of=myos.img skip=1 seek=1 bs=512 count=2879
在 bin 生成的镜像文件后补上空白,成为合适大小的软盘镜像,一共2880个扇区,略过第一个
用软盘启动系统
-
将myos.img下载到windows
-
VMWare创建空的虚拟机
2.1 文件 - 创建新的虚拟机 - 典型
2.2 稍后安装操作系统
2.3 其他
2.4 一路next 完成
2.5 虚拟机设置,去掉CD/DVD选项中“启动时连接”
2.6 网络,选择“仅主机模式”,勾选“启动时连接”(好像无所谓)
2.7 添加软盘驱动器 使用软盘映像 找到myos.img -
启动虚拟机
从此可以开始制作你的操作系统之旅。
为什么是从 0x7C00 开始?
IBM一开始就是这么设定的,后来为了兼容一直延续。参考:
https://www.glamenv-septzen.net/en/view/6
上一篇: 南北朝时期的主力兵是骑兵 他们的装备到底是什么样的
下一篇: 好用的sql语句合集