offsetregistry存的什么(register与volatile的区别及应用场景)
offsetregistry存的什么(register与volatile的区别及应用场景)解决问题:注意:C 编译器有自己的优化方式,不使用register也可能做优化。所以register关键字在高版本编译器中已经不用显示声明。比如,register关键字在c 11中被弃用,c 17中被删除,所以如果把代码适配到C 高版本的话,需要修改makefile 在CMAKE_CXX_FLAGS 中增加 -Wno-error=register所以,如果我们进行一段频繁的运算,则存储变量肯定要花费不少时间。所以C/c 语言允许将局部变量的值存放在寄存器中,这样需要时就直接搬用,不必再经过内存,从而提高运算速度。应用场景:某个算法函数内部对某个数据进行大量频繁的计算,但是又追求算法处理性能。
引言在嵌入式c开发或多线程开发的程序中,因为追求数据处理速度、追求共享数据实时性等,会对代码进行深度优化,甚至会考虑到CPU的寄存器层面。那么,与寄存器相关的特殊类型都有哪些呢?分别应用在哪些场景呢?
我们在前半部分介绍常见的register和volatile区别和使用场景,然后在文章后半部分进行cpu和寄存器的简单介绍。
register解决问题:
一般变量的值都是存储在内存中(当程序需要用到哪一个变量的值,由控制器发出指令将内存中该变量的值送到运算器,完了如果需要存储,再从运算器将数据送到内存中存放)。
所以,如果我们进行一段频繁的运算,则存储变量肯定要花费不少时间。所以C/c 语言允许将局部变量的值存放在寄存器中,这样需要时就直接搬用,不必再经过内存,从而提高运算速度。
应用场景:
某个算法函数内部对某个数据进行大量频繁的计算,但是又追求算法处理性能。
注意:C 编译器有自己的优化方式,不使用register也可能做优化。所以register关键字在高版本编译器中已经不用显示声明。比如,register关键字在c 11中被弃用,c 17中被删除,所以如果把代码适配到C 高版本的话,需要修改makefile 在CMAKE_CXX_FLAGS 中增加 -Wno-error=register
volatile解决问题:
volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,不再把变量从内存装入CPU寄存器中,从而可以提供对特殊地址的稳定访问。
volatile的意思是让编译器每次操作该变量时,一定要直接从内存中真正取出,而不是使用已经存在寄存器中的备份。
应用场景:
一般说来,volatile用在如下的几个地方:
1) 中断服务程序中修改的供其它程序检测的变量需要加volatile;
2) 多任务环境下各任务间共享的标志变量前,应该添加上volatile进行修饰;
3) 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义;
示例代码和运行效果#include <windows.h>
#include <thread>
using namespace std;
volatile bool flag = false;//唤醒状态
int result = 0; //注意:此变量不应该使用volatile进行修饰
void wake_up(const int num)
{
flag = true;
cout << "线程 " << num << " [id= " << this_thread::get_id() << "] wake_up" << endl;
}
//线程要做的事情
void thread_run(const int num int n)
{
while(1)
{
if (false == flag)
{
cout << "线程 " << num << " [id= " << this_thread::get_id() << "] wait..." << endl;
Sleep(1000);
}
else
{
for (int i = 0; i < n; i )
{
result ;
cout << "线程 " << num << " [id= " << this_thread::get_id() << "] result=" << result << endl;
}
return;
}
}
}
int main()
{
thread first(thread_run 1 5); //子线程1
thread second(thread_run 2 5); //子线程2
thread third(thread_run 3 5); //子线程3
thread fouth(wake_up 4); //子线程4
int temp = 0;
while (temp < 10)
{
Sleep(100);//单位是 毫秒
cout << "主线程result=" << result << endl;
temp ;
}
first.join(); //主线程要等待子线程执行完毕
second.join();
third.join();
fouth.join();
return 0;
}
volatile int result = 0; //使用volatile 进行修饰,编译器内部无法使用register对result 进行修饰,所以会出现读出(打印)数据显示异常的情况。
int result = 0;//不使用volatile 进行修饰,编译器内部默认使用register对result 进行修饰,打印数据显示正常。
(后半部分属于简单的科普内容,更详细的信息大家可以自行到网上搜一下)
计算机主要硬件分布计算机上有许多硬件: CPU、内存、USB、显卡等 它们由不同的总线(Bus) 相连。
计算最强的 CPU 和存储最快的 Memory 之间由北桥芯片连接。
北桥芯片专门用来处理那些 IO 较快的数据 最典型的例子就是 CPU 与 内存之间的交互。
南桥芯片用于接收那些 IO 没那么快的数据 如键盘、音频、网卡、显卡等硬件输入。
备注:为什么要区分南桥北桥呢? 因为 南桥的 IO 较慢 如果只有一根总线来接受所有数据 那么当低速的 IO 占用总线的时候 势必会阻塞高速的 IO。
图片来自网络
CPU的组成控制器 – 把内存中的指令 数据等读入到寄存器中
寄存器 – 用来暂存指令数据等处理对象
运算器 – 负责运算从内存读入到寄存器的数据
时钟 – 负责发出cpu开始计时的时钟信号
图片来自网络
寄存器、缓存、内存的关系图片来自网络
寄存器
寄存器是cpu的组成部分 是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的时序逻辑电路,但这种时序逻辑电路只包含存储电路。
寄存器是有限存储容量的高速存储部件,它们可用来暂存指令、数据和位址。寄存器分为通用寄存器和特殊寄存器 cpu访问寄存器的速度是最快的 但是寄存器的容量非常小。
缓存
缓存是cpu的一部分 位于cpu中。在没有缓存之前 cpu一直都是在内存中读取数据的 但由于两者速度差异 cpu每次都要等内存的’回信’ 缓存的设计是用来解决cpu与内存速度差异问题。
cpu内一般有3级缓存。假设一个8核的cpu 每个核都有自己独立的L1 Cache和L2 Cache 而L3 Cache是8核共享的。内存的数据会先加载到共享的L3 Cache中 再加载到每个核心独有的L2 Cache 最后进入到最快的L1 Cache。离核心越近 等级越高 速度越快 L1 Cache缓存最小 速度最快。
内存
内存又称主存,也称内存储器和主存储器。它用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。它是CPU能直接寻址的存储空间,由半导体器件制成。特点是存取速率快。
它是外存(硬盘、软盘、光盘、U盘等)与CPU进行沟通的桥梁,计算机中所有程序的运行都在内存中进行,内存性能的强弱影响计算机整体发挥的水平。只要计算机开始运行,操作系统就会把需要运算的数据从内存调到CPU中进行运算,当运算完成,CPU将结果传送出来。
内存的运行决定计算机整体运行快慢。
总结处理速度排序,cpu从寄存器读取最快 接下来是缓存 接下来是内存。
原创不易,欢迎点赞、收藏、关注!