这是 bilibili-[完结] 2020 南京大学 “操作系统:设计与实现” (蒋炎岩) 的课程笔记

本讲内容:
- 串行程序的状态机模型
- 状态机模型的应用
- 并发程序的状态机模型
- 理解并发程序的执行

文章目录

  • 串行程序的状态机模型
    • 有限状态机(Finite State Machine)
    • x86-64的栗子
  • 状态机模型:应用
    • 应用(1):Time-Travel Debugging
    • 应用(2):Record & Repaly
  • 并发程序的状态机模型
  • :star:理解并发程序的执行
    • 栗子:实现互斥

串行程序的状态机模型

有限状态机(Finite State Machine)

有向图G(V, E)

  • 节点->状态

  • 边->状态转换

  • 边上的label代表执行某个状态

操作系统上的程序执行时,状态是有限的,

  • 寄存器
  • 内存:代码、数据、堆栈(暂时假设内存静态分配)

构造有限状态机

  • 每个不同的 configuration 都是状态机的节点

    • s=(M,R) 属于 V,代表某个时刻程序内存/寄存器的快照
    • 16m的内存就有2的24m次方种不同的状态
  • s=(M,R)的下一个状态是执行 M[R[%rip]] 处的指令得到 s_1 = (M_1, R_1)
    • 取出PC指针处的指令、译码、执行、写回数据
    • (s, s_1) 属于 E

大部分状态有唯一的后续状态(deterministic)

我们学习的大部分算法都是 deterministic 的

程序 = 有限状态机

不确定的指令可能有多个状态(non-deterministic)的指令可能有多个后续状态

  • (时间)rdtsc/rdtscp

    • 获取处理器的时间戳用于精确定时
  • 机器状态 rdrand

    • 处理器自身提供的随机数指令
    • 读取处理器上的白噪声生成随机数
    // rdrand.c
    #include <stdio.h>
    #include <stdint.h>int main() {uint64_t val;asm volatile ("rdrand %0": "=r"(val));printf("rdrand returns %016lx\n", val);
    }
    
    ❯ vim rdrand.c
    ❯ gcc rdrand.c
    ❯ ./a.out
    rdrand returns da53e8a19ebdb3d1
    ❯ ./a.out
    rdrand returns cb075a76ba90effd
    ❯ ./a.out
    rdrand returns fde2ddfb5c7a2bf3
    ❯ ./a.out
    rdrand returns 10d0889b7c044cdc
    
  • 系统调用 syscall

    • 一般应用唯一不确定的来源
    • read(fd, buf, size) 返回值不确定、buf中的数据不确定,比如从键盘输入

x86-64的栗子

运行在 ring3(低特权级)的应用程序

  • 通用寄存器 16 个

    • rax\rbx\rcx\rdx\rsi\rbp\rsp
    • r8 ~ r15
  • PC 指针/机器状态
    • rip\rflags\cs\ds\es\fs\gs
  • 内存
    • 操作系统分配;通过procfs查看

这些状态都能被gdb观察到

  • info registers 列出所有寄存器
  • /proc/[pid]/maps 有内存映射信息
// minimal.S
.globl foo
foo:movl $1,    %eaxmovl $1,    %edimovq $s,    %rsimovl $(e-s),    %edxsyscallmovl $60,    %eaxmovl $1,    %edisyscalls:.ascii "\033[01;31mHello World\033[0m\n"
e:// code
.fill 1 << 20, 1, 0xcc// data
.section .data
.fill 2 << 20, 1, 0xff//bss
.section .bss
.fill 3 << 20
❯ gcc -c minimal.S
❯ ld minimal.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
❯ ./a.out
Hello World

程序可以执行,我们用gdb调试这个程序

❯ gdb a.out
(gdb) starti
Starting program: /tmp/tmp/a.out Program stopped.
0x0000000000401000 in foo ()
(gdb) info registers  # 查看寄存器状态
rax            0x0                 0
rbx            0x0                 0
rcx            0x0                 0
rdx            0x0                 0
rsi            0x0                 0
rdi            0x0                 0
rbp            0x0                 0x0
rsp            0x7fffffffdf00      0x7fffffffdf00
...
...
rip            0x401000            0x401000 <foo>
eflags         0x200               [ IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0(gdb) info inferiors # 查看程序的进程信息Num  Description       Executable
* 1    process 14178     /tmp/tmp/a.out
(gdb) !cat /proc/14178/maps # 查看进程内存中信息
00400000-00401000 r--p 00000000 103:07 538911                            /tmp/tmp/a.out
00401000-00502000 r-xp 00001000 103:07 538911                            /tmp/tmp/a.out
00502000-00702000 rw-p 00102000 103:07 538911                            /tmp/tmp/a.out
00702000-00a02000 rw-p 00000000 00:00 0                                  [heap]
7ffff7ff9000-7ffff7ffd000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffd000-7ffff7fff000 r-xp 00000000 00:00 0                          [vdso]
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
(gdb)

状态机模型:应用

在计算机硬件上的应用:高性能处理器实现

  • 超标量处理器

    • insight :允许在状态机上跳跃
  • 在计算机系统上的应用:程序分析技术
    • 静态分析:根据程序代码推导出状态机的性质
    • 动态分析:检查运行时观测到状态机的执行

应用(1):Time-Travel Debugging

GDB的隐藏功能

  • target record-full 开始记录(需要程序开始执行)
  • record stop 结束记录
  • reverse-step/reverse-stepi 时间旅行调试

对syscall指令不适用,因为side-effect难以准确定义

应用(2):Record & Repaly

在程序执行时记录信息,结束后重现程序的行为

  • 确定的程序不必记录
  • 假设s0执行1000000条确定的指令之后得到 s1
    • 那么只需要记录 s0 和 1000000
    • 就能通过“再执行一次”推导出 s1

Record&Repaly: 只需要记录 non-deterministic 的指令的效果(side-effect)

  • (单线程)应用程序

    • syscall\rdrand\rdtsc
  • (单处理器)操作系统
    • mmio\in\out\rdrand\rdtsc\中断
    • QEMU内置了 record/repaly

并发程序的状态机模型

系统中有n个线程,则并发程序的状态:

  • s= (M,R1,R2,…,Rn)
  • 并发程序执行的每一步都是不确定的

多线程程序可以看成是若干个单线程程序。在任意时刻,状态的转换就是 “选择一个线程执行一条指令”:

  • 选择线程 1 执行:(M,R1)→(M1′,R1′),得到状态 (M1′,R1′,R2,…,Rn);
  • 选择线程 2 执行:(M,R2)→(M2′,R2′),得到状态 (M2′,R1,R2′,…,Rn);
  • 选择线程 n 执行:(M,Rn)→(Mn′,Rn′),得到状态 (Mn′,R1,R2,…,Rn′);

n 个线程的并发程序,若每个线程执行 m 条指令,就算所有指令都是确定的,不同的执行顺序也多达 n^O(mn),这个状态机太大了。

就算是合并确定的状态,只要有共享内存,状态空间就很难画出了

  • 而且还不考虑编译优化、多处理器之间的可见性等问题

刚才介绍了各种状态机的应用,都需要为多线程重新设计

  • 共享内存是 non-determinism 的重要来源
  • time-travel debugging/record & replay 需要记录内存访问的数据
  • 自动测试要考虑如何探索线程调度
  • … …

⭐️理解并发程序的执行

程序

  • 指令序列的静态描述

    • 是非常概括、精简的
    • 所以行为有时候难以理解——循环、递归、分支的组合和不确定的共享内存

状态机

  • 所有动态行为的集合

    • 静态时的分支、循环全部被展开成了顺序结构
    • 大量的冗余和重复(verbose)
    • 行为明确、容易理解

栗子:实现互斥

希望实现 lock/unlock 保证:

  • (顺序)编译优化不能越过 lock/unlock
  • (原子)lock 返回后,unlock之前,其他线程的lock不能返回
  • (可见)unlock 之前执行的写操作,在unlock之后对其他线程可见
void do_sum(){for(int i = 0; i < n; i++){lock(); // 保证顺序、原子性、可见性// critical section;临界区sum++;// lock和unlock之间的代码被保护起来了unlock();}
}

Peterson 算法: 代码

int turn, x = 0, y = 0;void thread1() {[1] x = 1;[2] turn = T2;[3] while (y && turn == T2) ;[4] // critical section[5] x = 0;
}void thread2() {[1] y = 1;[2] turn = T1;[3] while (x && turn == T1) ;[4] // critical section[5] y = 0;
}

假设:机器每次原子地执行一行代码,内存访问立即可见。

证明:

Safety: 坏事永远不会发生。

  • 不存在一条从初始节点到错误状态的路径。

Liveness: 好事永远会发生。

  • 不存在无穷长的路径。

【并发2】理解并发程序的执行相关推荐

  1. C++程序的执行过程

    要理解一个程序的执行过程,首先要理解什么是编译器.我们用C语言写的程序,计算机只能识别机器语言(二进制指令),计算机并不能理解.因此,必须 将C语言转换为机器语言.编译器就是用来实现这一功能的.编译器 ...

  2. 多少并发量算高并发_如何理解:程序、进程、线程、并发、并行、高并发?

    作者:大宽宽 链接:http://tinyurl.com/wx5xxho 在这里你可以了解: 为啥大家说的进程的意思有出入? 为啥并发那么难理解? 为啥高并发不仅仅是"高"+&qu ...

  3. 如何理解:程序、进程、线程、并发、并行、高并发?

    在这里你可以了解: 为啥大家说的进程的意思有出入? 为啥并发那么难理解? 为啥高并发不仅仅是"高"+"并发"的意思? 为啥这些概念到了现实当中就不一样了? 进程 ...

  4. 对线程与进程的区别以及对多线程并发的理解

    一.线程与进程的区别 先简单说说线程与进程的概念: (1)进程是指一个内存中运行的应用程序,比如在Windows系统中,一个运行的exe就是一个进程. (2)线程是指进程中的一个执行流程. 区别: 一 ...

  5. 高并发的理解和使用场景-----特意区别和多线程的关系

    一,高并发的理解 1.概念:就是短时间内遇到大量操作请求,导致站点服务器/db服务器资源被占满甚至严重时直接导致宕 2.影响:没有做高并发预处理的系统会给用户很差的体验感: 3.系统好坏的衡量:衡量一 ...

  6. 对于高并发的理解及实践方案

    目录 01 如何理解高并发? 02 高并发系统设计的目标是什么? 2.1标题宏观目标高并发绝不意味着只追求高性能,这是很多人片面的理解. 2.2 微观目标 2.2.1 性能指标 2.2.2 可用性指标 ...

  7. 第二十节: 深入理解并发机制以及解决方案(锁机制、EF自有机制、队列模式等)

    一. 理解并发机制 1. 什么是并发,并发与多线程有什么关系? ①. 先从广义上来说,或者从实际场景上来说. 高并发通常是海量用户同时访问(比如:12306买票.淘宝的双十一抢购),如果把一个用户看做 ...

  8. 深入理解并发/并行,阻塞/非阻塞,同步/异步

    北京 | 深度学习与人工智能 12月23-24日 再设经典课程 重温深度学习阅读全文> 正文共3359个字,11张图,预计阅读时间:9分钟. 1.阻塞,非阻塞 首先,阻塞这个词来自操作系统的线程 ...

  9. 深入理解并发的关键字-volatile

    volatile是Java提供的一种轻量级的同步机制.Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量,相比于synchronized(synchronized通常称为 ...

最新文章

  1. 云炬创业政策学习笔记20210106
  2. 【NLP】文本分类还停留在BERT?对偶比学习框架也太强了
  3. linux下删除文件名乱码文件
  4. 合成未来宝宝照片_[萌主争霸]2020年台历宝宝投票评选开始啦!快来给你喜欢的萌宝投票吧~...
  5. BizTalk动手实验(十七)ODBC适配器使用
  6. MRF,马尔科夫随机场
  7. Web API-基本认知
  8. Warshall算法求传递闭包
  9. React脚手架---CRA
  10. SpringCloud-Gateway网关
  11. 云计算大数据中心(清明作业)
  12. 阿里云网盘内测地址,阿里云网盘申请内测资格链接
  13. 汉字Collection
  14. 爬取网易云热门音乐歌单
  15. 搜狐畅游薪酬公开,这是件好事么?-看点-虎嗅网
  16. Flutter学习笔记 --多子元素组件
  17. 压缩感知(Compressed Sensing)
  18. WMI 查询服务导致服务器CPU非常高!
  19. Spring框架中PO,BO,VO和POJO的区别
  20. Android跳转到系统通知管理页面

热门文章

  1. %cd%及%~dp0批处理命令的详解
  2. Shiro 与 Spring框架整合基本配制说明
  3. 一口气学会发布自己的地图查询系统
  4. python mysql blob_Mysql的BLOB操作
  5. 19. 最小乘车费用
  6. SuSE Linux 9下FTP、Telnet、图形终端服务的基本配置
  7. 根据背景图片计算文字颜色(实用、赞)
  8. 献给毕业生:五百强各大行业简介+面试流程+tips
  9. 【HZNUOJ】【IT名人】乔治•斯蒂比兹
  10. 解决Oracle表空间不足的情况