// 上一篇:最近最少使用(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. Java 编写小程序,下载指定网页上的所有图片

    使用Java编写一个小程序,可以根据指定的网页地址,下载网页中的所有图片:使用到网络编程.线程池.IO和UUID的技术.具体代码如下: import java.io.File; import java ...

  2. noip普及组2007 奖学金

    奖学金 描述 某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金.期末,每个学生都有3门课的成绩:语文.数学.英语.先按总分从高到低排序,如果两个同学总分相同,再按语文成绩 ...

  3. HIVE—索引、分区和分桶的区别

    一.索引 简介 Hive支持索引,但是Hive的索引与关系型数据库中的索引并不相同,比如,Hive不支持主键或者外键. Hive索引可以建立在表中的某些列上,以提升一些操作的效率,例如减少MapRed ...

  4. 8.8.2 Final关键字

    final表示不可改变的含义   1.采用final 修饰的类不能被继承 2.采用final 修饰的方法不能被覆盖 3.采用final 修饰的变量不能被修改 4.final修饰的变量必须显示初始化(该 ...

  5. @media实现网页自适应中的几个关键分辨率

    不同分辨率设备或不同窗口大小下网页布局经常是不同的,一不小心就会发生错位.可以利用@media screen实现网页布局的自适应,但是怎样兼容所有主流设备就成了问题.到底分辨率是多少的时候设置呢?首先 ...

  6. 常用px,pt,em换算及区别

    pt (point,磅):是一个物理长度单位,指的是72分之一英寸. px (pixel,像素):是一个虚拟长度单位,是计算机系统的数字化图像长度单位,如果px要换算成物理长度,需要指定精度DPI(D ...

  7. Django编写RESTful API(四):认证和权限

    欢迎访问我的个人网站:www.comingnext.cn 前言: 按照前面几篇文章里那样做,使用Django编写RESTful API的基本功能已经像模像样了.我们可以通过不同的URL访问到不同的资源 ...

  8. selenium元素定位大全

    要做自动化,首先要了解页面结构,要了解页面结构,就要了解页面元素的定位方法 在使用selenium webdriver进行元素定位时,通常使用findElement或findElements方法结合B ...

  9. pickle模块的使用python3

    Python的pickle模块实现了基本的数据序列和反序列化.通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储:通过pickle模块的反序列化操作,我们能够从文件 ...

  10. Servlet中Response对象应用1(输出简单文字、实现文件下载)

    通过response对象可以实现很多功能,下面的代码都是在myeclipse上实现过的,整理下路,以备后用. response对象应用1 1向客户端发送简单消息 A利用已经声明的对象,调用其getOu ...