控制结构(7): 程序计数器(PC)
// 上一篇:最近最少使用(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」。
这样调试器又有机会把所有的协程区分开来,可以为每个协程产生独立的调用链条。
我为什么要从进程->多线程->单线程这样绕一圈分析呢?因为,存在另一个更本质的问题:
怎样在多进程情况下,多进程之间的一个调用链条串起来。
显而易见的方案:
在所有的调用链条上传id,显然,这样的做法可以满足需求,但是所有的调用接口都需要知道这个id参数。做法2:
在进程出口和入口处传id,进程内部用独立的线程跑每一次的独立调用链条,通过唯一线程id来区分,线程里执行的代码只需从当前线程局部存储就可以拿到当前调用链id,这样不需要在线程内部不需要到处传id,只在进程之间出口和入口传id。但问题也明显:我们不可能无限创建线程。于是考虑3:
在进程出口和入口处传id,进程内部采用独立的协程跑每一次的独立调用链条,通过唯一协程id来区分,协程里执行的代码只需从当前协程局部存储就可以拿到当前调用链id,这样不需要在协程内部到处传id,只需在进程之间出口和入口传id。
很好,第3种方案是可行的,只需要你的语言支持协程。这样我们就可以在多进程之间的调用链条上有每次调用的独立id(也就是pc,程序计数器)。通过这一个id,可以给这样的调用链实现调试器。取代已经落后的基于单线程函数调用栈的调试器。
在不支持协程的语言里怎么办?考虑一种弱化的方式:函数闭包+支持函数内写任意代码(嵌套的class、嵌套的function,嵌套的import、include等加载其他模块代码等接口)。一个支持闭包的函数,函数闭包范围内的代码都可以访问函数的参数变量。这个函数的参数变量就是这个函数闭包范围内代码一次执行的「local storage」,此时方案改进为:
- 在进程出口和入口处传id,进程内通过函数闭包的方式执行用户代码(把这个外围的大闭包函数称为scope-function),用户代码可以通过函数参数变量获取当前调用链条的id。
- 由于这个函数闭包内的代码都可以访问到这个scope-function的参数,因此scope-funciton内部的代码不需要到处传id),那么一个问题是,scope-function内的代码如果import另一个模块的代码,不就超出当前scope-function的范围了吗?
- 很简单,通过scope-function的参数,替换掉scope-function内部执行的import,这个import的实现里,我们只要把scope-function的局部存储用来做需要import的代码的新scope-function的参数即可。
- 用户代码仍然不需要到处传id。
程序计数器,古老术语的内涵。本文的核心是说明“用独立id串起动态执行的有序调用链条”,不是进程、线程、协程等已有设施。
控制结构(7): 程序计数器(PC)的更多相关文章
- 控制结构(7) 程序计数器(PC)
// 上一篇:最近最少使用(LRU) // 下一篇:线性化(linearization) 程序的每一行都是一个状态,对应的行指令.同步的情况下同一个pc一直自增,异步的时候,分裂出一个新的子pc,独立 ...
- 系统架构师考试——程序计数器 PC, 指令寄存器IR、状态寄存器SR、通用寄存器GR
● 计算机执行程序时,在一个指令周期的过程中,为了能够从内存中读指令操作码,首先是将__(9)___的内容送到地址总线上. (9)A.程序计数器PC B.指令寄存器IR C.状态寄存器SR ...
- 运行时数据区--程序计数器(PC Register)
程序计数器(PC Register) 这里的计数器(Program Counter Register)并非为广义上所指的物理寄存器,JVM中的PC寄存器(程序计数器)是对物理PC寄存器的一种抽象模拟, ...
- 关于程序计数器(PC)和条件控制转移 引起的性能差异
关于PC(程序计数器) 冯 ·诺伊曼计算机体系结构的主要内容之一就是“程序预存储,计算机自动执行”! 处理器要执行的程序(指令序列)都是以二进制代码序列方式预存储在计算机的存储器中,处理器将这些代码逐 ...
- java虚拟机-程序计数器PC Register
什么是程序计数器? 程序计数器是一块 较小 的内存空间,它可以看做是当前线程所执行的字节码的 行号指示器 :在虚拟机的概念模型里(仅仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解 ...
- Java内存区域之程序计数器--《深入理解Java虚拟机》学习笔记及个人理解(一)
Java虚拟机程序计数器 在书上的P39页 程序计数器干嘛的? 有了它,字节码解释器才可以知道下一条要执行的字节码指令是哪个. 无论是取下一条指令还是分支.循环.跳转.中断.线程恢复,都需要这个程序计 ...
- 大脸猫讲逆向之ARM汇编中PC寄存器详解
i春秋作家:v4ever 近日,在研究一些开源native层hook方案的实现方式,并据此对ARM汇编层中容易出问题的一些地方做了整理,以便后来人能有从中有所收获并应用于现实问题中.当然,文中许多介绍 ...
- 20155339平措卓玛 Exp1 PC平台逆向破解(5)M
20155339平措卓玛 Exp1 PC平台逆向破解(5)M 实践内容 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数. 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖 ...
- 单片机pc指针
单片机的PC是指程序计数器(Program Counter).程序计数器PC用于存放下一条将要执行的指令地址,是一个16位专用寄存器,不能通过MOV指令来操作,对用户来说是不可见的.当执行一条指令时, ...
随机推荐
- NLP入门(七)中文预处理之繁简体转换及获取拼音
在日常的中文NLP中,经常会涉及到中文的繁简体转换以及拼音的标注等问题,本文将介绍这两个方面的实现. 首先是中文的繁简体转换,不需要使用额外的Python模块,至需要以下两个Python代码文 ...
- C# Word文档中插入、提取图片,文字替换图片
Download Files:ImageOperationsInWord.zip 简介 在这篇文章中我们可以学到在C#程序中使用一个Word文档对图像的各种操作.图像会比阅读文字更有吸引力,而且图像是 ...
- Java开发笔记(六十五)集合:HashSet和TreeSet
对于相同类型的一组数据,虽然Java已经提供了数组加以表达,但是数组的结构实在太简单了,第一它无法直接添加新元素,第二它只能按照线性排列,故而数组用于基本的操作倒还凑合,若要用于复杂的处理就无法胜任了 ...
- java的ArrayList源码摘要
ArrayList本质上是一组对象数组,ArrayList有三种构造方法 1.指定长度创建ArrayList,2.默认长度为10创建.3,用旧的集合创建一个ArrayList. 对ArrayList的 ...
- C# 消息队列-MSMQ
MQ是一种消息中间件技术,所以它能够支持多种类型的语言开发,同时也是跨平台的通信机制,也就是说MQ支持将信息转化为XML或者JSon等类型的数据存储到消息队列中,然后可以使用不同的语言来处理消息队列中 ...
- jsp基础语言-jsp注释
JSP注释可分为客户端注释和服务器端注释. 客户端注释:用户可通过浏览器中的源代码查看,且这种注释可以加入JSP表达式. 语法:<!-- 客户端注释[<%=表达式%>] --> ...
- js 动态添加class封装(es6语法)
export function hasClass(el, className) { let reg = new RegExp('(^|\\s)' + className + '(\\s|$)') re ...
- Vue:如何在地图上添加自定义覆盖物(点)
目录 如何在地图上添加自定义覆盖物(点) 首发日期:2019-1-25 如何在地图上添加自定义覆盖物(点) 此文重点是在地图上标点,所以就省去引入百度地图的步骤了. 先给一下最终的效果. 这个效果主要 ...
- Odoo POS会员积分当钱用如何设置?
问题提问 设定积分规则1元积1分.而后每1积分可以当1分钱用,POS中能处理吗? 解决方案 1) 设定服务类型产品“积分”,其单价为0.01,收入科目为“销售费用” 2) 设定积分计划:积分规则是,订 ...
- Android 7.0及以上使用OpenCL
由于从Android 7.0, API 24, 开始, 系统将阻止应用链接至非公开NDK库, 所以, 使用libOpenCL.so时与面向低版本的Android平台有所不同, 需要把依赖的非公开NDK ...