2024年3月9日发(作者:)

几年之前,CPU的性能还主要取决于CPU的主频,经过超摩尔定律的发展后,没过多长

时间CPU的主频速度就已接近“极限”,使得单单靠提高CPU的主频来提升性能变得非常困

难。

目前,Intel、AMD等CPU生产商都转而采用了多核技术来提升CPU性能,甚至提出了

群核CPU的概念。这意味着,要充分发挥多核CPU的性能,程序就必须采用多线程并发计算

的方式,传统的串行程序将会极大地浪费多核CPU的运算能力!

C++是上世纪80年代诞生的语言,它的前身是同样风靡全球的C语言。一直以来它都以

代码效率卓越著称,进入多核时代后,因为C++标准库没有提供多线程支持,要用C++开发

出充分利用多核CPU的程序将面临很大挑战。

于是,在C++社区出现了不少优秀的库以支持并行编程,如各种跨平台的线程库,Open

MP,Clik++等。另一方面,微软也从Win2K开始不断地加入线程池API(如QueueUserWork

Item),C++09标准也明确地表示要加入多线程的支持。

使用线程库编写并行程序的优点是可以精确调度各个线程,并且可以在所有C++编译器

里使用。不过要充分发挥多核CPU的性能,还要考虑很多因素,主要难点有:

死锁 编写多线程必然会遇到同步问题,如果同步控制出现问题,就可能出现死

锁或脏数据。

线程之间通信 使用何种机制在多个线程之间通信?即要保证通信数据同步又要

保证效率。

负载平衡 分配到每个线程的工作量要尽量平衡,避免一个线程忙一个线程闲的

情形发生。

资源匹配 程序应该使用多少个线程?过少的线程不能充分利用CPU的多核优

势,而过多的线程会造成线程调度过于频繁同样会降低效率。

OpenMP是目前比较流行的C++并行编程方式,它通过在代码中插入专用的pragma编译

指令来指示编译器把串行代码编译成并行程序。

它的优点是易于使用,几乎不用修改原代码就可对老程序进行并发支持的改造。问题

是它必须要有编译器的支持,尽管目前不少编译器都提供了OpenMP的支 持,但它毕竟不

是C++的一部分,甚至它都不是真正意义上的C++库。。

现在,我们又有了一个新选择:Intel Thread Building Blocks(TBB,线程构建模块)。

TBB是一个开源的C++模板库,能够运行在 Windows、Linux、Macintosh以及UNIX等系统

上,只要是标准的C++编译器都可以使用它。

以下是程序测试的实验案例和测试结果:

for ( int j = 0; j < num; j++ )

{

k[j]=j;

for(int p=0;p<10000;p++)cout(p); //进行很大的for循环,又调用函数,主要

目的就是让它耗时间;

}

for(int i=0;i

printf("%d ",k[i]);

很显然,这是一个经典的单线程程序,其中的for(int p=0;p<10000;p++)cout(p); 是

一个内嵌了提高程序复杂性的函数的大循环,主要是为了提高程序的额外开销,以便于我们

能够明显的观察到多线程程序与单线程程序之间的性能差异。整个for程序执行的流程如下

所示:

j=0 -> k[j]=j -> 进行复杂运算 -> j!=j++并继续下一个循环num-1?:退出循环

并顺序显示k[num]中的内容

有一点需要注意的是,由于单线程的程序是顺序执行的,所以上面这个程序第二个for

语句其实是可以不必使用的,可以将它内嵌入第一个for语句中:

for ( int j = 0; j < num; j++ )

{

k[j]=j;

for(int p=0;p<10000;p++)cout(p); //进行很大的for循环,又调用函数,主要

目的就是让它耗时间;

printf("%d ",k[i]);

}

这样可以减少程序额外开销,但是对于多线程程序来说,这点开销是必须的,如果输出

必须是顺序的话,那我们有必要控制它的输出顺序,否则将会出现乱序输出--尽管结果是正

确的,但是输出的顺序却是我们不想看到的。当然,第二个for语句所增加的开销,远远比

不上并行程序运行时所节约的开销。我们使用Intel的openmp技术来创建多线程的程序,

因为openmp技术够直观,也很容易去分析与理解,所以我们无需去调用底层API就能够轻

易的实现多线程编程。要使用openmp技术就要安装Intel编译器及下面的openmp组件,

Intel编译器可以很好的与Visual Stdio整合在一起,起码要求是你的计算机上必须安装

了Visual C++6.0。当然,安装完之后我们必须进行一些设置,以Visual Stdio 2008为例,

如果我们想要使用openmp技术的话,我们须在VC项目下右边的“资源管理器”中点“属

性”--“C/C++”--“语言”--有个“openmp支持”选项,选“是(/openmp)”即可。另

外我们必须在程序中插入的头文件。

做完了最基本的设置之后,我们就可以开始改程序了:

#pragma omp parallel for //就多了这么一句,在我的电脑上就快了75%;

for ( int j = 0; j < num; j++ )

{

k[j]=j;

for(int p=0;p<10000;p++)cout(p);

}