[C/C++学习] restrict 关键字

本篇博客主要谈论 C 语言关键字 restrict,只用于修饰指针,功能是帮助编译器进行优化!值得注意的是,优化需要就事论事,经过分析:如果发现确实优化不了,就不优化了。不加 restrict 关键字修饰的指针,编译器一定不进行优化!

一、定义

1、概念

关键字 restrict 只用于限定指针,表明本指针是访问一个数据对象的惟一且初始的方式。

2、目的

关键字的用意是充分发挥多处理器(CPU 只有 1 个)的并行性。注意和并发作区别。
并发是基于时间片轮转的,故而从宏观上看,各个进(线)程是一起运行的,微观上是串行的。并行就像是多向车道一样(车道数目------核数),各个进(线)程运行互不干扰。

二、实例

1、利用并行拆分循环

void add(const double *x, const double *y, double *res, int n)
{    
	int i;

	for(i = 0; i < n; ++i)         
		res[i] = x[i] + y[i];
}

例1、例2的前提:假设数组 x 和数组 y 内存无重叠,但是数组 x 和数组 res 内存有重叠:

例1 假设如图 1 所示:res[i] 依赖于 res[i - 1] 的值,无法优化。

[C/C++学习] restrict 关键字_第1张图片

例2 假设如图 2 所示:res[5] 依赖于 res[0] 的值,没有办法去做优化。

[C/C++学习] restrict 关键字_第2张图片

例3的前提:假设数组 x , y , res 内存均有重叠:

例3 假设如图 3 所示,res[0…3] 的计算没有依赖性,res[4…5] 存在依赖性,无法优化。

[C/C++学习] restrict 关键字_第3张图片

总结:内存重叠存在的话,是无法进行优化的,因为不存在一劳永逸的办法解决这个问题。

最理想的情形
假设 x , y , res 三者指向的内存空间不会重叠, 如果这个函数将在多处理器的环境下执行,编译器可能会做这样的优化:把一个循环拆成两个循环,一个处理器计算 res[0…2],另一个处理器计算 res[3…5],两个处理器可以同时工作,使计算时间理论上缩短一半,同时保证了结果的正确性。如果程序员已经能够保证内存不重叠的话,就有必要指定 restrict 允许编译器进行优化。

2、 Target Code Optimizer(目标代码优化器)

说明:例子为源代码是不合适的,因为目标代码优化器操作的对象是目标代码(x86 的汇编语言),但是可以帮助我们理解使用关键字 restrict 进行优化的过程。

int arr[10];
int* par = arr;    //既可以通过 par 也可以通过 arr 访问本数组 

restrict int* p1 = (int*)malloc(10 * sizeof(int)); 

for(int i = 0; i < 10; ++i)
{    
	par[i] += 5;    //语句1    
	p1[i] += 5;     //语句2    
	arr[i] *= 2;    //语句3    
	par[i] += 3;    //语句4    
	p1[i] += 3;    	//语句5
} 

p1 存在 restrict 修饰,含义就是 p1 所指向的空间只会由 p1 去修改,故而语句 2 和语句 5 可以合并为一句。arr 或者 par 都不能指定为 restrict,二者深层次原因是不同的—— arr 不能指定是唯一性不满足,par 不能指定是唯一性和初始性同时不满足。
优化后的结果可能是这样的,语句 5 和并入语句 2;修改语句 2,删除语句 5:

int arr[10];
int* par = arr;    //既可以通过 par 也可以通过 arr 访问本数组 

restrict int* p1 = (int*)malloc(10 * sizeof(int)); 

for(int i = 0; i < 10; ++i)
{    
	par[i] += 5;    //语句1    
	p1[i] += 8;     //语句2    
	arr[i] *= 2;    //语句3    
	par[i] += 3;    //语句4
}

你可能感兴趣的:(C/C++,restrict)