多核与多线程

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

多核平台下的多线程编程示例zz2008-07-15 10:41PC时代引来了多核平台,在硬件性能不断提升的情况下,我们有没有做好迎接它的准备?在单核时代,程序是单线程运行,由于Intel引入了超线程的技术,使我们还在单核时代就领略了将会在多核平台下成为主流的多线程编程技术。但是有一个显而易见的问题:如果没有软件的支持,那么多核平台将无法发挥它的优势,那么我们转变到多核平台所需要的代价将变得没有意义。所以,幸运的是,多线程编程技术出现在了多核平台之前,并且早已为多核平台打下了基础,而且芯片公司也早已预见到了这种软硬必须同步发展的必要性。Intel在其最新的编译器中,已经为软件多线程编程提供了多种方案;当然,本篇只是一篇多线程编程的实验结论,并不是探求多线程编程技术理论的文章,所以不想对其深入探讨。本篇所作的实验是在Intel Core2 Quad Q6600 2.4G四核处理器平台下的试验性程序,其编程平台选用的是Microsoft Visual Stdio 2008专业版+Intel C++编译器10.1。 首先我们先来看一段例程: for ( int j = 0; j < num; j++ )
{
k[j]=j;
for(int p=0;p<10000;p++)cout(p); //进行很大的for循环,又调用函数,主要目的就是让它耗时间;
}
for(int i=0;iprintf("%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);
}
for(int i=0;iprintf("%d ",k[i]); 这就可以了,我们发现,仅仅只是多了一条“#pragma omp parallel for”而已,但是就多了这么一句,就是程序在我的计算机上快了近75%(估测,非精确计算)。原先程序使用了近32秒,但是现在程序仅用了8秒,这证明了程序运行确实是大幅提高了性能。那我们该着么理解这仅多出来的一条语句呢?很简单,这显然是编译器控制指令,它会在程序编译的时候自动分析for语句,将它拆成多个线程来运行。这样做的好处是我们能够很简单的就创建多线程程序而无需去了解其底层的运行机制,但是它也有一些局限性,使得我们不得不考虑以下几个问题: 1.对for语句我们必须使用for(i=xxx;x<或>xxx;i的运算法则不能含有变量)其中xxx为固定的常数的形式的循环才能够使用#pragma omp parallel for (当然sections结构也可以进行拆分),也就是说在需要进行多线程化的循环必须是定长的、可预见的,当然使用低层API我们可以动态的创建线程,也就不存在定长循环的问题。 2.对所要拆分线程的for语句,规定不得存在迭代相关性。因为创建线程后线程之间是独立运行的,如果线程之间存在相关性,将会使得程序产生混乱的运行结果。当然使用底层的API我们可以更有效的控制和操作各个线程的合作与运行,但是在openmp就无法实现了。如果要进行多线程化的循环出现了迭代相关性,那我们必须重新设计for循环,以等效的无相关性的循环代替它,但是代价就是提高了程序的复杂性。 3.数据竞争。我们必须保证,各个线程之间不会对同一个外部或公共变量进行操作(哪怕是读操作都是危险的),在此情况下,Intel提供了两种方案:一种是尽可能的使用私有或局部变量;一种是获取公共变量的副本。 总之,openmp的编程技术确实是非常的方便与美妙,只要我们在程序设计的时候遵守了

以上几个法则即可。当然,openmp的功能要远为强大的多,包括更复杂的线程分配方案、更复杂的操作等,但是却能很简单的应用。不过对本例来说还用不着那些技术,仅 #pragma omp parallel for就足亦。下面我将这次试验的源代码完整的贴上来,以使各位能够更全面的来了解一下程序的结构://多线程试验程序#include "stdafx.h"
#include
#include
#include#define num 100
void cout(int p) //复杂运算函数,仅是让他做复杂计算;
{
p=(1+2+3+4+5+6+7+8+9+10)/(9*8*7*6*5*4*3*2*1);
for(int k=0;k<10000;k++);
}
int main(int argc, char* argv[])
{
int k[num];
char c='0';
printf("请选择想执行的程序:\n1.单线程示例程序\n2.多线程示例程序\n3.退出\n注:这两段程序相同所不同的是第二段为多线程程序,计算性能应从电脑提示程序已经开始时计算!\n请输入:");//这个for是整个循环主题了,也就是程序的框架;但是这个for不是最耗性能的,所以不用多线程化;
for(;c!='3';) //如果c=='3'的话就直接退出,但是首次运行时赋值为'0',所以不会退出;
{
c=_getch(); //选择输入;
if(c=='1') //这个if就是第一段程序的总体了,可以与下个else if比较发现仅少了 #pragma omp parallel for 语句;
{
printf("1\n第一段程序已经开始了,该段程序是单线程程序\n");
for ( int j = 0; j < num; j++ )
{
k[j]=j;
for(int p=0;p<10000;p++)cout(p); //开始做无用功!既进行很大的for循环,又调用函数,主要目的就是让它耗时间;
}
for(int i=0;iprintf("%d ",k[i]);
printf("\n第一段程序已经结束\n请输入:");
} else if(c=='2') //第二段主程序;
{
printf("2\n第二段程序已经开始了,该段程序和第一段程序相同,只是多了#pragma omp parallel for,我们可以仔细观察它们的区别\n");
#pragma omp parallel for //就多了这么一句,在我的电脑上就快了75%;
for ( int j = 0; j < num; j++ )
{
k[j]=j;
for(int p=0;p<10000;p++)cout(p);
}
for(int i=0;iprintf("%d ",k[i]);
printf("\n第二段程序已经结束\n请输入:");
} else //稍微做的正规点,就加了这么一句;
printf("无该选项,请重新选过!\n请输入:");
}
return 0;






多核多线程编程中,怎么获得线程在哪个cpu核上运行?
悬赏分:20 - 解决时间:2009-5-13 18:59
如题

提问者: wdh128b -

一级最佳答案MSDN:
GetProcessAffinityMask

The GetProcessAffinityMask function retrieves the process affinity mask for the specified process and the system affinity mask for the system.


BOOL GetProcessAffinityMask(
HANDLE hProcess,
PDWORD_PTR lpProcessAffinityMask,
PDWORD_PTR lpSystemAffinityMask
);

Parameters
hProcess
[in] Handle to the process whose affinity mask is desired.
This handle must have the PROCESS_QUERY_INFORMATION access right. For more information, see Process Security and Access Rights.

lpProcessAffinityMask
[out] Pointer to a variable that receives the affinity mask for the specified process.
lpSystemAffinityMask
[out] Pointer to a variable that receives the affinity mask for the system.













求一个多线程的例程C++(API)
悬赏分:20 - 解决时间:2009-10-14 21:20
我是想在函数中等待键盘消息的传入,
如果没有传入,就等待,如果传入后就继续程序
最开始我想用sleep()
但用后发现,我其他正运行函数也都sleep了
后来我写了一个等待函数
大概就是
while( 1 )
{
if ( keydown )
break;
}
但内存耗损达到50%以上
现在想用多线程中的
WaitForMultipleObjects()
根据MSDN上面的信息,还有网上的信息
我试着编了几个
但不是无法运行,就是中途异常中断,或是没有效果
求高手给个多线程的简单例程

或者给个可以解决我这种不占耗内存的等待方法

提问者: youweidihao - 二级最佳答案#include
#include

typedef HANDLE HSEMAPHORE;

#define P(hHandle) ::WaitForSingleObject(hHandle, INFINITE)
#define V(hHandle) ::ReleaseSemaphore(hHandle, 1, NULL)
#define Semaphore(lInitial, lMaximum) ::CreateSemaphore(NULL, lInitial, lMaximum, NULL)
#define Thread(lpProc, lpParam) ::CreateThread(NULL, 0, lpProc, (LPVOID)lpParam, 0, NULL)
#define Wait(nCount, lpHandles) ::WaitForMultipleObjects(nCount, lpHandles, TRUE, INFINITE)

HSEMAPHORE n = Semaphore(0, 1);
HSEMAPHORE s = Semaphore(1, 1);
HSEMAPHORE e = Semaphore(100, 100);

UINT count = 0;

void Produce(){Sleep(1);}
void Consume(){Sleep(100);}

DWORD WINAPI Producer(LPVOID lpParameter)
{
while (true)
{
Produce();
P(e);
P(s);
count++;
printf("Producer: %d\n", count);
V(s);
V(n);
}
return 0;
}

DWORD WINAPI Consumer(LPVOID lpParameter)
{
while (true)
{
P(n);
P(s);
count--;
printf("Consumer: %d\n", count);
V(s);
V(e);
Consume();
}
return 0;
}

int main()
{
HANDLE hThreads[2];

hThreads[0] = Thread(Producer, (LPVOID)NULL);
hThreads[1] = Thread(Consumer, (LPVOID)NULL);

Wait(2, hThreads);
return 0;
}

相关文档
最新文档