// 上一篇:最近最少使用(LRU)
// 下一篇:线性化(linearization)


程序的每一行都是一个状态,对应的行指令。同步的情况下同一个pc一直自增,异步的时候,分裂出一个新的子pc,独立一颗子状态机。之所以要分裂一个pc是因为原来的pc后续的同步代码要用,而创建协程就会一开始就创建出一个新pc,这个pc专为协程里的状态机服务,则协程可以在异步点随时yield,也就是暂存独立的pc,跳转到旧pc去执行,然后再resume到新pc这里。基本上,就是两个状态机之间轮流占用时间片。一个独立的状态机一个pc,在同一个pc上的状态机片段,就可以在这个pc所代表的时间线上流式串起来,这就是所谓的react programming的原理,一个pc上面的流,就可以通过parser做filter,进而做成独立的pipeline.

多进程下,每个进程有独立id,每个进程的堆栈是独立的。

在多线程里,每个线程有独立的id,每个线程有独立的local storage,于是,调试器可以通过线程id和线程局部存储来标记不同线程上的调用链。因此,可以为不同的线程产生独立的函数调用堆栈,因为调试器可以把不同线程的函数调用链区分开来。

单线程里,一个函数的两次调用,他们的外围作用域是同一个,通过同一个外围作用域,一个函数的两次调用之间共享全局变量。同一个函数的两次调用所引发的后续调用链条,如果要区分开,需要各自一个独立的ID(类似上一段的pc),比如,在调用链条上到处传递这个ID可以做到。那么,有没有办法不显式传递这个ID,直接通过全局变量拿到呢?

一般来说是有困难的,假设使用一个全局变量标记函数一次调用的id,在该函数第二次调用的时候,id要变,但是如果你直接改变同一个全局变量,则上一次调用链里拿到的该id就被修改了。所以,必需函数的每次调用都有一个独立的id变量来标记。那么问题来了,在函数调用链条中,怎样拿到自己的那次调用的id变量?

由于一般语言并没有基础设施标记函数在动态之行中的独立调用标记,没有办法区分开应该拿第几个id变量。如果一个语言能支持函数执行过程中动态获取自己所在调用链的独立id,那就是一个很赞的语言。协程(corotine)提供了一种这方面的支持,一个独立的协程所引发的调用链,可以取到当前协程,挂载在当前协程下的变量就是协程所在的「local storage」。

这样调试器又有机会把所有的协程区分开来,可以为每个协程产生独立的调用链条。

我为什么要从进程->多线程->单线程这样绕一圈分析呢?因为,存在另一个更本质的问题:

怎样在多进程情况下,多进程之间的一个调用链条串起来。

显而易见的方案:

  1. 在所有的调用链条上传id,显然,这样的做法可以满足需求,但是所有的调用接口都需要知道这个id参数。做法2:

  2. 在进程出口和入口处传id,进程内部用独立的线程跑每一次的独立调用链条,通过唯一线程id来区分,线程里执行的代码只需从当前线程局部存储就可以拿到当前调用链id,这样不需要在线程内部不需要到处传id,只在进程之间出口和入口传id。但问题也明显:我们不可能无限创建线程。于是考虑3:

  3. 在进程出口和入口处传id,进程内部采用独立的协程跑每一次的独立调用链条,通过唯一协程id来区分,协程里执行的代码只需从当前协程局部存储就可以拿到当前调用链id,这样不需要在协程内部到处传id,只需在进程之间出口和入口传id。

很好,第3种方案是可行的,只需要你的语言支持协程。这样我们就可以在多进程之间的调用链条上有每次调用的独立id(也就是pc,程序计数器)。通过这一个id,可以给这样的调用链实现调试器。取代已经落后的基于单线程函数调用栈的调试器。

在不支持协程的语言里怎么办?考虑一种弱化的方式:函数闭包+支持函数内写任意代码(嵌套的class、嵌套的function,嵌套的import、include等加载其他模块代码等接口)。一个支持闭包的函数,函数闭包范围内的代码都可以访问函数的参数变量。这个函数的参数变量就是这个函数闭包范围内代码一次执行的「local storage」,此时方案改进为:

  1. 在进程出口和入口处传id,进程内通过函数闭包的方式执行用户代码(把这个外围的大闭包函数称为scope-function),用户代码可以通过函数参数变量获取当前调用链条的id。
  2. 由于这个函数闭包内的代码都可以访问到这个scope-function的参数,因此scope-funciton内部的代码不需要到处传id),那么一个问题是,scope-function内的代码如果import另一个模块的代码,不就超出当前scope-function的范围了吗?
  3. 很简单,通过scope-function的参数,替换掉scope-function内部执行的import,这个import的实现里,我们只要把scope-function的局部存储用来做需要import的代码的新scope-function的参数即可。
  4. 用户代码仍然不需要到处传id。

程序计数器,古老术语的内涵。本文的核心是说明“用独立id串起动态执行的有序调用链条”,不是进程、线程、协程等已有设施。

控制结构(7) 程序计数器(PC)的更多相关文章

  1. 系统架构师考试——程序计数器 PC, 指令寄存器IR、状态寄存器SR、通用寄存器GR

    ● 计算机执行程序时,在一个指令周期的过程中,为了能够从内存中读指令操作码,首先是将__(9)___的内容送到地址总线上. (9)A.程序计数器PC    B.指令寄存器IR C.状态寄存器SR    ...

  2. 运行时数据区--程序计数器(PC Register)

    程序计数器(PC Register) 这里的计数器(Program Counter Register)并非为广义上所指的物理寄存器,JVM中的PC寄存器(程序计数器)是对物理PC寄存器的一种抽象模拟, ...

  3. 控制结构(7): 程序计数器(PC)

    // 上一篇:最近最少使用(LRU) // 下一篇:线性化(linearization) 程序的每一行都是一个状态,对应的行指令.同步的情况下同一个pc一直自增,异步的时候,分裂出一个新的子pc,独立 ...

  4. 关于程序计数器(PC)和条件控制转移 引起的性能差异

    关于PC(程序计数器) 冯 ·诺伊曼计算机体系结构的主要内容之一就是“程序预存储,计算机自动执行”! 处理器要执行的程序(指令序列)都是以二进制代码序列方式预存储在计算机的存储器中,处理器将这些代码逐 ...

  5. java虚拟机-程序计数器PC Register

    什么是程序计数器? 程序计数器是一块 较小 的内存空间,它可以看做是当前线程所执行的字节码的 行号指示器 :在虚拟机的概念模型里(仅仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解 ...

  6. Java内存区域之程序计数器--《深入理解Java虚拟机》学习笔记及个人理解(一)

    Java虚拟机程序计数器 在书上的P39页 程序计数器干嘛的? 有了它,字节码解释器才可以知道下一条要执行的字节码指令是哪个. 无论是取下一条指令还是分支.循环.跳转.中断.线程恢复,都需要这个程序计 ...

  7. 大脸猫讲逆向之ARM汇编中PC寄存器详解

    i春秋作家:v4ever 近日,在研究一些开源native层hook方案的实现方式,并据此对ARM汇编层中容易出问题的一些地方做了整理,以便后来人能有从中有所收获并应用于现实问题中.当然,文中许多介绍 ...

  8. 20155339平措卓玛 Exp1 PC平台逆向破解(5)M

    20155339平措卓玛 Exp1 PC平台逆向破解(5)M 实践内容 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数. 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖 ...

  9. 单片机pc指针

    单片机的PC是指程序计数器(Program Counter).程序计数器PC用于存放下一条将要执行的指令地址,是一个16位专用寄存器,不能通过MOV指令来操作,对用户来说是不可见的.当执行一条指令时, ...

随机推荐

  1. 【社交系统研发日记五】ThinkSNS+如何计算字符显示长度?

    今天我们来聊一下可能很多人都会头疼的东西:显示长度. 需求是这样的,在字符的显示上,两个英文单词才占一个中文或者其他语言的显示长度.如下: 上面排的是两个英文字母,一个汉字,一个Emoji.你会发现, ...

  2. mysql shutdown and kill

    --mysqladmin shutdown If you execute mysqladmin shutdown when connecting to a local server using a U ...

  3. 如何用CSS和jQuery实现一个侧滑导航菜单

    为了建立导航菜单,让我们先看看html结构:<!DOCTYPE html><html lang="en"><head> <meta cha ...

  4. css动画过渡

    css动画过渡css代码: .div03{ width:100px;height:100px;background: rebeccapurple;color: #fff; -webkit-transi ...

  5. Vue动态组件

    前面的话 让多个组件使用同一个挂载点,并动态切换,这就是动态组件.本文将详细介绍Vue动态组件 概述 通过使用保留的 <component> 元素,动态地绑定到它的 is 特性,可以实现动 ...

  6. java参数传递

    关于方法的参数传递,java中方法的参数传递均为值传递,根据传递的类型以及方法中对参数的处理可以分为2类: 1.传递参数为基本数据类型,因为是值传递,所以方法运行结束后对传递参数的值无影响. 2.传递 ...

  7. RQNOJ 201 奥运大包围:LIS + 拼链成环

    题目链接:https://www.rqnoj.cn/problem/201 题意: 开始时n(n<=1000)个人手拉手围成一个圈. 后来这些人中的一些按顺序向里面出圈形成一个新圈.从而使原圈形 ...

  8. 用户管理-linux基础

    用户管理 useradd -u -g -G(附加组) ,-c -d -s -r(创建系统用户)   -M (不创建家目录)    思考:删除user1用户家目录,如何还原.        可以#cp ...

  9. 菜单栏-Place(放置)菜单

  10. HTML图像

    HTML 图像- 图像标签( <img>)和源属性(Src) 在 HTML 中,图像由<img> 标签定义. <img> 是空标签,意思是说,它只包含属性,并且没有 ...