菜鸟笔记
提升您的技术认知

操作系统笔记

进程,线程,协程与并行,并发进程线程协程的区别死锁进程,线程,多线程i++的线程安全性同步和异步孤儿进程和僵尸进程/proc进程信息linux中的分段和分页互斥量 mutex线程进程间通信进程创建进程优先级进程的基础知识进程与线程的区别(面试题)线程的控制(创建,终止,等待,分离)可重入 VS 线程安全死锁的概念一级缓存和二级缓存的理解一句话解说内存屏障 Memory barrierbrk(), sbrk() 用法详解malloc/free函数的简单实现一文讲透 “进程、线程、协程”Linux进程状态线程池的陷阱linux内核学习之进程和线程进程与线程的区别和联系内存寻址linux IO子系统和文件系统读写流程Page cache和buffer cache的区别与联系漫谈linux文件IO多线程和多进程的区别内存泄漏字节、字、位、比特的概念和关系如何避免死锁ANSI是什么编码?CPU寻址范围(寻址空间)CPU 使用率低高负载的原因创建多少个线程合适操作系统下spinlock锁解析、模拟及损耗分析线程堆栈堆和栈的内存分配堆和栈的概念和区别堆和栈的区别,申请方式,程序的内存分配什么是 POD 数据类型Linux内存分配小结--malloc、brk、mmap系统调用与内存管理(sbrk、brk、mmap、munmap)进程描述和控制CPU执行程序的原理编译的基本概念Linux虚拟地址空间布局一个程序从源代码到可执行程序的过程程序的运行机制——CPU、内存、指令的那些事分页内存管理——虚拟地址到物理地址的转换深刻理解Linux进程间通信fork之后父子进程的内存关系fork之后,子进程继承了父进程哪些内容关于协程及其锁的一些认识对协程的一点理解std::thread join和detach区别CAS和ABA问题CAS算法锁和无锁无锁队列的实现Lock-Free 编程锁开销优化以及CAS

程序的运行机制——CPU、内存、指令的那些事

阅读 : 305
  • 序言
    说起计算机大家并不陌生,在计算机上又运行着各种程序,如QQ、微信等。这些程序有可以为我们做很多事情,能聊天、能玩游戏等等。那么这些看似复杂的程序在计算机中到底是怎么运行起来的呢?其实非常简单,我们不妨一起探讨一下。
    作为程序员我们必须理解CPU是如何运行的,特别是要弄清楚负责保存指令和数据的寄存器的机制。了解了寄存器,也就自然而然的理解了程序的运行机制。
  • CPU的构成
    在程序运行流程中,CPU所负责的就是解析和运算最终转换成机器语言的程序内容。CPU从功能上来看由寄存器、控制器、运算器、时钟构成。
CPU的构成 CPU是寄存器的集合体

寄存器:用来暂存指令、数据等处理对象。
控制器:负责把内存上的指令、数据等读入寄存器、并根据指令的执行结果来控制计算机。
运算器:负责运算从内存读入寄存器的数据。
时钟:负责发出CPU开始计时的时钟信号

  • 内存的作用
    内存指的就是计算机的主存储器,其主要负责存储指令和数据。CPU通过内存地址值来读取或写入指令和数据。注意:内存中的指令和数据会随着计算机的关机日自动清除。
    在理解了CPU和内存后,大家对程序的运行机制的理解是不是也加深了一些?程序启动后,根据时钟信号,控制器会从内存中读取指令和数据。通过对这些指令加以解析和运行,运算器就会对数据进行运算,控制器根据运算结果控制计算机。
  • 决定程序流程的程序计数器
    下面我们通过将123和456两个数相加,并将结果输出到显示器的实例,说一下程序计数器是如何工作的。
    当用户发出启动程序的指示后,操作系统会把硬盘中保存的程序复制到内存中。如下图是程序启动时内存内容的模型。

    操作系统把程序复制到内存后,会将程序计数器设定为0100(假设内存地址0100是程序运行的开始地址),然后程序便开始运行。CPU每执行一个指令,程序计数器的值就会自动加1。所以,程序计数器决定着程序的流程。
  • 指令
    从功能方面来看,机器语言指令可分为数据传送指令、算数指令、跳转指令、call/return指令。

    数据传送指令:寄存器和内存、内存和内存、寄存器和外围设备之间的数据读写操作
    运算指令:用累加寄存器执行算术运算、逻辑运算、比较运算和位移运算
    跳转指令:实现条件分支、循环、强制跳转等
    call/return指令:函数的调用/返回调用前的地址

  • 函数调用
    call指令和return指令是如何实现函数调用的呢?
    其实call指令在将函数的入口地址设定到程序计数器之前,call指令会把调用函数后要执行的指令地址存储在名为栈的主存内。函数处理完毕后,再通过函数的出口来执行return命令。return命令的功能就是把保存的栈中的地址设定到程序计数器中。如下面的图示,MyFunc函数被调用之前,0154地址保存在栈中。MyFunc函数的处理完毕后,栈中的0154地址就会被读取出来,然后再被设定到程序计数器中。

程序调用函数示例 函数调用中程序计数器和栈的职能