CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  专题开发/技术/项目 >  英特尔多核计算技术

windows环境下多内核开发的注意点。

楼主BlueTrees(蜗牛)2006-08-06 16:47:53 在 专题开发/技术/项目 / 英特尔多核计算技术 提问

原来单线程或者多线程的程序在多内核或者多CPU的硬件结构下开发需要注意的事项。  
   
  1、主要考虑的是线程的亲缘性,应当让同一个进程内的线程尽量在同一个CPU上获得调度(操作系统会搞这件事情),这样CPU不会因反复更新缓存浪费时间,因为同一个进程的线程在同一个地址空间中。这样说来,使用多线程并没有获得太大的好处,还是在同一个CPU上调度的。  
   
  2、等待函数的使用,因为多核心,所以不要怕占用过多的CPU时间片,在某些情况下应该尽量用循环察看变量值的方式处理线程的同步(使用interLockXXXXX),而不要使用等待函数进行系统调用,CPU切换进入核心态的代价是很高的,如果超过一定的循环次数再使用等待函数也不迟,所以不是长时间等待的同步不要用等待函数。  
   
  3、可以把一些多线程的设计更改为多进程的方式,多进程的方式更容易在2个CPU上同时获得调度,效率更高。 问题点数:0、回复次数:26Top

1 楼goldencode()回复于 2006-08-08 14:19:06 得分 0

楼上的这样是帮不了AMD的~!  
  Top

2 楼goldencode()回复于 2006-08-08 14:23:56 得分 0

楼主说的很好!  
  几个问题,  
  现在多核是share   cache的,那么线程切换到不同的CPU还需要重新load   cache吗?  
  CPU切换到核心态究竟有多高的代价?感觉一不需要换页,二也不需要额外保留堆栈什么的啊.  
  第三点我同意,不过linux下也许不需要.  
   
  Top

3 楼goldencode()回复于 2006-08-08 14:24:31 得分 0

问题一应该是切换到不同核心  
  Top

4 楼BlueTrees(蜗牛)回复于 2006-08-08 16:05:48 得分 0

多线程切换的开销,不是内存映射表,而是线程上下文,主要是线程堆栈的切换和恢复寄存器消耗时间。  
   
  如果在一个CPU上切换同一个进程的线程,遇到的问题是缓存选中,线程的堆栈没在缓存中。  
   
  不在同一个进程的线程切换需要花费的代价就更高了,主要是切换内存描述符表还有一些描述符表,比较庞大,不仅仅是缓存有没有选中,更重要的是,CPU内部的一些地址转换的寄存器都要切换,即便共享缓存,切换正好选中缓存,但是CPU内部的寄存器更新也消耗大量的时间。  
   
  线程的亲缘性就是要避免在2个CPU核心上切换2个不同进程的线程,同一个进程的线程尽量在同一个核心上调度,这样就避免切换内存描述符表了(不仅是缓存,主要是核心内部的寄存器更新消耗)。  
   
  这是多线程程序提高性能的设计重点。  
   
  切换到核心态,大概消耗2000个时钟周期(相对于其他指令而言其实很恐怖了),这是微软的文档上说的,关于临界区的使用,里面讨论了切换到核心态的代价。临界区是线程同步对象,但是它是用户态的对象,他就是先循环处理2000次左右,再进入核心态的。可以参考临界区的设计。  
   
  需要经常同步的多线程程序这些也是要注意的,特别是服务器程序设计,对于客户端而言,除非你参加比赛,这些代价基本看不出来。  
   
  跨进程的线程同步只能使用核心态同步对象,这是没办法的。  
   
  最后是,一个Windows的Bug不知道搞好了没有。  
   
  线程在windows下经常得不到调度,有时候进入核心态等待的时候,等待的对象已经受信还会得不到调度,甚至长时间得不到调度,所以,在另外一个线程在受信一个等待对象之后最好使用sleep(0),以便其他沉睡的线程可以得到调度,特别是当你需要等待那个沉睡的线程去完成某个工作的时候,不切换一下,会很长时间不进行合理调度的。  
   
  这个是windows的老毛病了,是口传身授的一个办法,没有什么道理,也没见微软回应过,反正一直这么搞就可以,不这么搞就会动不动卡在那里一会儿,让你百思不得其解。Top

5 楼BlueTrees(蜗牛)回复于 2006-08-08 16:19:44 得分 0

死锁的解决办法,数据结构上说得很明白了,简单的方案就是不允许交叉持有资源,必须按序持有和释放资源。  
   
  还有就是更简单的,一次性全部申请和一次性全部释放的办法。  
   
  这个,我想只要是程序员都应该知道的吧?  
   
  当然,依靠一张资源持有图和每个线程的获取资源顺序图理论上是可以进行精确控制的,但是,往往不可能在程序运行时精确的确定持有资源的顺序,所以,也就是理论罢了。  
   
  至于复杂的解锁算法和干预,一般没人去搞,仅仅停留在理论上罢了。  
  Top

6 楼goldencode()回复于 2006-08-08 21:54:00 得分 0

多线程切换的开销,不是内存映射表,而是线程上下文,主要是线程堆栈的切换和恢复寄存器消耗时间。  
   
  如果在一个CPU上切换同一个进程的线程,遇到的问题是缓存选中,线程的堆栈没在缓存中。  
   
  不在同一个进程的线程切换需要花费的代价就更高了,主要是切换内存描述符表还有一些描述符表,比较庞大,不仅仅是缓存有没有选中,更重要的是,CPU内部的一些地址转换的寄存器都要切换,即便共享缓存,切换正好选中缓存,但是CPU内部的寄存器更新也消耗大量的时间。  
   
  线程的亲缘性就是要避免在2个CPU核心上切换2个不同进程的线程,同一个进程的线程尽量在同一个核心上调度,这样就避免切换内存描述符表了(不仅是缓存,主要是核心内部的寄存器更新消耗)。  
   
  这是多线程程序提高性能的设计重点。  
   
  切换到核心态,大概消耗2000个时钟周期(相对于其他指令而言其实很恐怖了),这是微软的文档上说的,关于临界区的使用,里面讨论了切换到核心态的代价。临界区是线程同步对象,但是它是用户态的对象,他就是先循环处理2000次左右,再进入核心态的。可以参考临界区的设计。  
   
  需要经常同步的多线程程序这些也是要注意的,特别是服务器程序设计,对于客户端而言,除非你参加比赛,这些代价基本看不出来。  
   
  跨进程的线程同步只能使用核心态同步对象,这是没办法的。  
   
  最后是,一个Windows的Bug不知道搞好了没有。  
   
  线程在windows下经常得不到调度,有时候进入核心态等待的时候,等待的对象已经受信还会得不到调度,甚至长时间得不到调度,所以,在另外一个线程在受信一个等待对象之后最好使用sleep(0),以便其他沉睡的线程可以得到调度,特别是当你需要等待那个沉睡的线程去完成某个工作的时候,不切换一下,会很长时间不进行合理调度的。  
   
  这个是windows的老毛病了,是口传身授的一个办法,没有什么道理,也没见微软回应过,反正一直这么搞就可以,不这么搞就会动不动卡在那里一会儿,让你百思不得其解。  
  ------------------------------------------------------------------------------------  
  给你个建议,回答问题抓住重点.随便说一句,我说你说的好是因为你题目选对了:)  
  对于问题一,你前后回答充满漏洞,前面你说主要是因为更新缓存造成性能低下,后面你又说主要是CPU内部寄存器切换更花时间.即使这样请问,到底进程切换和线程切换在寄存器件使用上有哪些不同?差别到底有多大?和把两个线程并行处理带来的好处比付出的代价到底有多大?还有,既然已经是两个进程了,两个进程在内核间如何分配是用户的问题还是操作系统的问题?如果操作系统已经将两个进程分配到两个核心上了,他们会如何使用smart   cache?会发生你说的那种情况吗?关于你的结论 "这样说来,使用多线程并没有获得太大的好处,还是在同一个CPU上调度的"不需要多说,明显是荒谬的.请看Intel编译器对Super   PI算法的多线程优化在多核上的成绩.这就是单进程在一个CPU上的多线程调度.  
  关于第二个问题,你的回答是切换到内核状态的代价是2000个时钟,请给出出处.还有临界区需要进入核心态吗?如果不需要,那这和多核有什么关系,人人都知道用临界区比内核对象更快.  
  最后你说的死锁的问题是想说明什么?  
   
  Top

7 楼BlueTrees(蜗牛)回复于 2006-08-09 09:05:47 得分 0

我就想说在windows下多线程的注意点,没想过要和你争论,呵呵。  
   
  你不明白的地方,我加以解释罢了,Top

8 楼goldencode()回复于 2006-08-09 09:19:22 得分 0

那你还是解释一下吧,否则像"这样说来,使用多线程并没有获得太大的好处,还是在同一个CPU上调度的"这样的结论太误导大家了吧.hehe.  
  Top

9 楼BlueTrees(蜗牛)回复于 2006-08-09 10:08:11 得分 0

关于亲缘性的结论,我说错了。  
   
  正确的说法是,应该小心的利用亲缘性的特性,以便发挥最大性能,设置得不好,会导致只有一个核心在充分运转,而没有利用双核的性能。  
   
  通常,在同一个进程中的线程我们会设置它在同一个CPU上运行,防止CPU的缓存失效。但是,利用这个特性的时候,会导致,只有一个核心在发挥作用,没有享受到多核的好处。  
   
  切换到核心态的时间,我记得是在msdn上看到的,但是找不到原文了。重新找了一下,现在能找到的说法,是大约600个CPU指令,如果是流水线,平均每周期3条指令,那么消耗200个时钟左右,如果没有流水线,或者流水线指令预测失败,那么4周期/指令,大约就是2400个周期。  
   
  我说临界区的例子,是说,要学习微软设计临界区的办法,怎么避免线程同步的时候进入核心态。Top

10 楼goldencode()回复于 2006-08-09 11:06:12 得分 0

通常,在同一个进程中的线程我们会设置它在同一个CPU上运行,防止CPU的缓存失效。但是,利用这个特性的时候,会导致,只有一个核心在发挥作用,没有享受到多核的好处。  
  ------------------------------------------------------------------------------------  
  那要看你如何设置了,正常操作下你说的情况不需要担心.  
   
  ------------------------------------------  
  切换到核心态的时间,我记得是在msdn上看到的,但是找不到原文了。重新找了一下,现在能找到的说法,是大约600个CPU指令,如果是流水线,平均每周期3条指令,那么消耗200个时钟左右,如果没有流水线,或者流水线指令预测失败,那么4周期/指令,大约就是2400个周期。  
  ------------------------------------------  
  600个CPU指令的说法比较准确,至于要多少时钟周期那要看具体CPU了,现在CORE   2   DUO是四条流水线,也就是说执行效率比以前提高33%,而且还有指令合并技术,在有些时候甚至可以一次取5条指令,因此效率提升更高.  
  但不管怎么说这是个传统多线程问题和多核关系不大.和架构有关,所以core   2   duo才这么强.  
  Top

11 楼dishening7()回复于 2006-08-18 16:43:30 得分 0

衷心感谢BlueTrees   (蜗牛)   为某些技术白吃不厌其烦的解答,我是第一次来这个坛子,本来挺兴奋的,一位找到了家,没想到这里的垃圾还真是不少,明明是技术白吃,却还装出一幅大牛的样子,对别人的技术帖横挑鼻子竖挑眼,真的很佩服BlueTrees   (蜗牛)   ,这么有耐心,另外,希望能多发这种技术性的帖子!!!  
   
  明眼人都看得出来,到底是谁开口AMD,闭口“core   2   duo才这么强”,我只是路过,但是在是看不过眼了。Top

12 楼Charles_L(@-@)回复于 2006-08-22 11:57:34 得分 0

BlueTrees   (蜗牛)   高手!Top

13 楼icdesigner2004()回复于 2006-09-02 15:05:37 得分 0

BlueTrees   (蜗牛)   不仅技术过硬还很谦虚的,难得哦Top

14 楼apzhang(ZHANG)回复于 2006-09-02 22:57:35 得分 0

双核双CPU的系统应该怎么样设计程序Top

15 楼apzhang(ZHANG)回复于 2006-09-02 22:57:53 得分 0

来提高系统的性能Top

16 楼dayoo(Dayoo Ding)回复于 2006-09-29 07:41:04 得分 0

哦Top

17 楼middle(中间件)回复于 2006-10-24 06:38:51 得分 0

楼主说的三个问题都有待商榷:  
   
  1.   这个app   developer恐怕做不到吧?kernel   scheduler不支持的话,无论如何都不行;kernel   scheduler支持的话,app   developer不用做什么也可以。  
   
  2.   楼主对preemptive   OS的原理恐怕不熟悉。如果你在用户态空转,对于系统是否会进入内核态是没有影响的。  
   
  3.   这个对,不过也是比较基本的意思。Top

18 楼BlueTrees(蜗牛)回复于 2006-10-25 22:16:25 得分 0

1、App   Developer可以做到,你看一下Windows的相关介绍就可以了。  
   
  2、这不是我说的,这是微软的设计指导说的,如果只有一个CPU空转是没有意义的,在windows系统中即便设定空转也不会进入,因为,单CPU如果你不释放CPU,其他线程如果不是被抢先调度,那么在空转时,没有谁可以改变临界区的状态,如果被抢先调度,那么已经进入核心态了,空转无意义的,但是,多CPU时,你在一个CPU上空转,另外一个线程在另外一个CPU上调度,是有可能改变临界区状态的,所以可以避免进入核心态的开销。看样子,我学的比你深多了,你不过就是记住了几个英文单词,而我却不明白你想说什么。  
   
  3、空间换效率罢了。  
   
  app   developer看见这个我就忍不住想笑了。  
   
  为了考研,我不得不去看原版的操作系统原理,不过我在上班的时候,还是用母语的,母语特别亲切,而且便于思维。Top

19 楼middle(中间件)回复于 2006-10-27 06:19:16 得分 0

1.   Scheduling是内核统一考虑的,没有任何一个进程能够单独影响系统。这个是OS的责任。Windows下可以做到归可以做到,但我认为不是user   space的开发能够影响的。  
   
  2.   如果你在一个进程内空转,OS还是会peempt这个进程。除非你能够在kernel   space空转并且明确禁止kernel   preemption。  
   
  3.   这个我就不多说了,无论如何在这一点上你也没有说错。  
   
  总而言之,你所说的经验是在multi-core上如何进行kernel   space开发的经验。我不确定这是不是你的本意,但是从你第一篇帖子看来,并没有明确说明这一点。而且既然你强调Windows下开发,估计再kernel   space下也做不了什么。Top

20 楼middle(中间件)回复于 2006-10-27 21:43:07 得分 0

上面的帖子我说楼主的第3点“至少没有说错”。其实还是有争议的。Thread和Process从scheduling的角度讲基本没有不同。但是process的switch   overhead要比thread大得多。  
   
  另外为了实现相同的语义,process往往要使用复杂而且overhead很大的IPC。  
   
  所以把thread特意变为process一般在效率方面是没有意义的。Top

21 楼BlueTrees(蜗牛)回复于 2006-10-27 22:09:09 得分 0

2、空转的时候,绝大多数不会被抢先,因为,空转的次数很少,花费的时间很短,一般来说会短于时间片。此外,在windows下,如果使用同步对象进入核心态,线程会被排到等待队列中去,这样很浪费时间。空转即便被抢先了,那也排在就绪队列中,容易得的调度。空转的时候,线程的堆栈不会切换,这样,缓存也不会失效。一旦线程切换了,那就要付出代价了,所以空转是有效果的Top

22 楼middle(中间件)回复于 2006-10-28 07:22:57 得分 0

2.   楼主上一贴的解释是有些道理的。我对interlockXXX不熟,希望楼主再说明一下。  
   
  从楼主的解释看来,interlockXXX应该就是Windows提供的让进程在kernel   space空转并且disable   preemption的API。我的理解对吗?Top

23 楼BlueTrees(蜗牛)回复于 2006-10-28 11:33:40 得分 0

我的理解不是这样,原子操作是CPU的一些特殊指令。  
   
  CPU在任何时候,中断不会发生在单条指令的执行中间,所以,任何指令都是“原子”的,单个CPU不存在单个指令的原子问题,简单的加法在执行中不会被抢断,问题在于多CPU的时候,2个CPU有可能访问同一个内存地址,并且执行操作,这样就会发生问题。  
   
  通常多CPU的系统中有一个协调机制的,CPU引脚通常会有一个lock引脚,当lock引脚处于低电平时,其他CPU不能访问数据总线,这样确保操作的原子性。  
   
  这是特殊的CPU指令,但是,在程序中不应该直接使用某个汇编语句,那样会产生兼容性问题,所以,原子操作都表现为操作系统提供的服务。  
   
   
   
  Top

24 楼BlueTrees(蜗牛)回复于 2006-10-28 11:36:37 得分 0

此外,原子操作是实现任何操作系统高级同步对象的基础,没有原子操作,操作系统就不可能提供同步对象。  
   
  这一点很重要,要铭记于心。Top

25 楼middle(中间件)回复于 2006-11-07 21:29:54 得分 0

BlueTrees,你上面两个帖子单独看说得都很好。但是问题是:你说的这种硬件级别的原子操作,互斥操作,总线锁,是不能被直接应用于user   space   programming的。  
   
  所以,如果你的这个帖子是希望告诉大家在Windows下开发针对多核优化应用程序的技巧的话,那么你必须告诉大家Windows的什么APIs如何用了这些硬件级别的操作,在user   space下又如何用这些APIs。这两点缺一不可。  
   
  你上面的描述不是单说第一点,就是单说第二点。就是没有结合起来描述。所以等于什么技巧都没有说。Top

26 楼middle(中间件)回复于 2006-11-07 21:33:08 得分 0

退一步说,如果你不希望说得特别深入,也可以只说user   space如何应用哪些APIs。然后抽象地说明这些API的语义。如果你用这用方法,就不要在描述中插入对硬件级别操作的描述。  
   
  总而言之,软件设计是分层次结构的,不同层次的东西不能混在一起描述。Top

相关问题

关键词

得分解答快速导航

  • 帖主:BlueTrees

相关链接

  • CSDN Blog
  • 技术文档
  • 代码下载
  • 第二书店
  • 读书频道

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo