cpu_relax( )-----对自选循环等待(spin-wait loops)操作的优化【转】

cpu_relax()-----对自选循环等待(spin-wait loops)操作的优化

转自:http://www.doc100.net/bugs/t/173547/index.html

   在lock_timer_base()函数中看到在for循环操作中调用了cpu_relax(),本来以为是要让出CPU,调度其他进程运行,但是看代码之后发现完全不是这么回事。cpu_relax()中只有一条调用语句,调用的是rep_nop函数。rep_nop()函数如下:

 

static inline void rep_nop(void)
{
	asm volatile("rep; nop" ::: "memory");
}

只有一条简单的汇编语句,原来在论坛里看到过这条汇编语句,不是重复执行nop指令,"rep; nop"指令会被翻译成pause指令,到底是不是这样呢?反汇编一下看看,c代码如下:

 

#include <stdio.h>

static inline void rep_nop(void)
{
    asm volatile("rep; nop" ::: "memory");
}

int main(void)
{
    rep_nop();
    return 0;
}

文件名保存在nop.c,使用gcc编译成目标文件nop.o,命令如下:

 

 

gcc -c nop.c

使用objdump来反汇编,命令如下:

 

 

objdump -s -d nop.o

 

反汇编的结果如下图所示:


从图中可以看出"rep; nop"指令被翻译成pause指令,因此实际上rep_nop()函数执行了一次pause指令。关于这条指令,intel的指令手册《Instruction Set Reference, M-Z》中讲的比较详细,这里总结一下。

  pause指令的作用是:

    1)提升spin-wait loops(自旋循环等待)的性能。在执行一个 spin-wait loops时,Pentium4处理会遇到严重的性能损失,因为在循环退出时,处理器会检测到一个可能的内存顺序冲突。pause指令会向处理器提供一种提示,告诉处理器当前所执行的代码序列是一个spin-wait loop操作。大多数情况下,处理器会根据这个提示避开内存序列冲突,从而提高处理器的性能。正是基于此,建议在spin-wait loop中使用pause指令。

    2)pause指令的另外一个功能是让Pentium4处理器在执行spin-wait loop时可以减少电源的消耗。在等待资源而执行自旋等待时,Pentium4处理器以极快的速度执行自旋等待操作时,将会消耗很多电能,但使用pause指令则可以极大地减少处理器的电源消耗。

  PAUSE 指令在 Pentium4 处理器中引入,但它也是向前兼容的。在早先的 IA-32 处理器里,PAUSE 指令实际上就相当于 NOP 指令。Pentium4 处理器以一种 预延迟(pre-defined delay)的技术来实现 PAUSE 指令。这种延迟也是有限度的,并且在一些处理器上是零延迟。该指令不会改变处理器的处理器的状态。

  上面还提到一个概念就是内存顺序冲突(Memory order violation)。内存顺序冲突一般是由假共享引起,假共享是指多个CPU同时修改同一个缓存行的不同部分而引起的一个CPU的操作无效,当出现这个内存顺序冲突时,CPU必须清空流水线。

参考资料:

聊聊并发(五)——原子操作的实现原理

http://www.groad.net/bbs/read.php?tid-3373.html

时间: 2024-10-31 14:23:16

cpu_relax( )-----对自选循环等待(spin-wait loops)操作的优化【转】的相关文章

模态窗口其实就是在当前窗口调用系统的消息循环,响应用户的操作,将相关的消息发送到对应的窗口(转)

  上周准备在公司内部转岗,面了3个部门windows客户端相关的工作,最终拿到3个Offer,主要涉及C++和Windows两大块内容,C++的题目基本都答上了,Windows一直都是我的弱项,在这里记录一下Windows相关的题目.有些答不上的问题就没列出来,还有些问题忘了,下面的答案有些大部分是我自己的理解,有些是直接从网上copy的,有问题大家可以讨论. 1:GetMessage和PeekMessage的区别? GetMessage:获取消息队列中的一个消息,存入MSG中,并从消息队列中

SQL2005实现循环每一行做一定操作。

要对一个表的每一行做出比较复杂的操作,一般会想到用游标,今天想到使用SQL2005中的新函数ROW_NUMBER()和while循环来对每一行执行操作.示例代码如下: select Department_No as departmentNo,ROW_NUMBER() OVER(ORDER BY Department_No) AS rowNumber into #depTemp--建立临时表from departmentsdeclare @max int--获得最大的rowNumberselect

javascript for循环从入门到偏门(效率优化+奇特用法)_javascript技巧

一,for循环的基本写法 代码如下: 复制代码 代码如下: //例一for(var i=1;i<=10;i++) { alert(i); } 这段代码太简单了,我都不好意思拿出手.代码的执行结果是依次弹出1到10,PS:在早期的IE如IE6中,你把10改成10000,就能让用户一直点确定什么也不能干了哈哈--不要说是我出的主意. 由于这是一篇基础课程,所以我们回归正题来详细分析一下这段代码吧. for循环的结构都是类似的,任意一个for循环都是这样的: for(开始前;循环进行的条件;循环一次结

我这个循环怎么特别慢呢?怎么优化一下呢

问题描述 for(inti=0;i<rownum;i++){k=i%5;switch(k){case0:j++;CiHui[0,k,j]=dt.Rows[i]["Ciyu"].ToString();CiHui[1,k,j]=Pinyin.PinyinManager.Pinyin(dt.Rows[i]["Ciyu"].ToString(),3);//这是一个static方法break;default:CiHui[0,k,j]=dt.Rows[i]["C

【等待事件】等待事件系列(3+4)--System IO(控制文件)+日志类等待

 [等待事件]等待事件系列(3+4)--System IO(控制文件)+日志类等待   1  BLOG文档结构图     2  前言部分   2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~: ① 控制文件类等待 ② 日志类等待   2.2  相关参考文章链接 [推荐] 等待事件系列(1)--User I/O类型(下) http://blog.itpub.net/26736162/viewspace-2124435

Spin lock 与mutex 的区别--2011.01.06

POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API.线程同步(Thread Synchronization)是并行编程中非常重要的通讯手段,其中最典型的应用就是用Pthreads提供的锁机制(lock)来对多个线程之间共 享的临界区(Critical Section)进行保护(另一种常用的同步机制是barrier). Pthreads提供了多种锁机制:(1) Mutex(互斥量):pthread_mutex_***(2) Spin lock(自旋锁):

多线程同步-主线程等待所有子线程完成案例

http://blog.csdn.net/qiujuer/article/details/34862469 有时候我们会遇到这样的问题:做一个大的事情可以被分解为做一系列相似的小的事情,而小的事情无非就是参数上有可能不相同而已! 此时,如果不使用线程,我们势必会浪费非常多的时间来完成整个大的事情,而使用线程的话将会存在这样的问题: 主线程启动所有子线程并发执行后主线程就直接返回了,导致外部函数判读整个大的事情完成了,但是实际上并没有完成! 针对以上情况我想我会采用多线程方式执行同时解决主线程等待

oracle等待事件6——行高速缓存上的等待事件

1.row cache lock oracle将数据子典信息存于SGA内的行高速缓冲区(或dictionary cache),行高速缓冲区位于共享池内,可以通过如下命令进行确认: SQL> select pool,name,bytes from v$sgastat where name='row cache'; POOL          NAME                                          BYTES ------------ --------------

深入浅析Node.js 事件循环_node.js

Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. (来源于Javascript是单线程又是异步的,但是这种语言有个共同的特点:它们是 event-driven 的.驱动它们的 event 来自一个异构的平台.) Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现. Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件