IT专家为什么C中需要挥发物Word文档格式.docx
- 文档编号:16367224
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:20
- 大小:26.92KB
IT专家为什么C中需要挥发物Word文档格式.docx
《IT专家为什么C中需要挥发物Word文档格式.docx》由会员分享,可在线阅读,更多相关《IT专家为什么C中需要挥发物Word文档格式.docx(20页珍藏版)》请在冰豆网上搜索。
intdata;
intisbusy;
}MyHardwareGadget;
Nowyouwant
tosendsomecommand:
现在你想发送一些命令:
voidSendCommand(MyHardwareGadget*gadget,intcommand,intdata)//wait
whilethegadgetisbusy:
while(gadget-isbusy)//donothinghere.//setdatafirst:
gadget-
data=data;
//writingthecommandstartstheaction:
gadget-command=command;
Lookseasy,butitcanfailbecausethecompilerisfreetochangetheorderinwhichdata
andcommandsarewritten.Thiswouldcauseourlittlegadgettoissuecommandswiththe
previousdata-value.Alsotakealookatthewaitwhilebusyloop.Thatonewillbe
optimizedout.Thecompilerwilltrytobeclever,readthevalueofisbusyjustonceand
thengointoaninfiniteloop.That’snotwhatyouwant.
看起来很简单,但它可能会失败,因为编译器可以自由更改数据和命令的顺序。
这将导致我们的小工具使用前面的数据值发出命令。
还可以查看“忙循环”时的等
待。
这个会被优化。
编译器将尝试聪明一点,只读一次isbusy的值,然后进入一个
无限循环。
那不是你想要的。
Thewaytogetaroundthisistodeclarethepointergadgetasvolatile.Thiswaythe
compilerisforcedtodowhatyouwrote.Itcan’tremovethememoryassignments,itcan’t
cachevariablesinregistersanditcan’tchangetheorderofassignmentseither:
解决这个问题的方法是将指针小部件声明为volatile。
这样,编译器就被迫执行您
所编写的操作。
它不能删除内存分配,不能缓存寄存器中的变量,也不能改变分配
的顺序:
Thisisthecorrectversion:
这是正确的版本:
voidSendCommand(volatileMyHardwareGadget*gadget,intcommand,intdata)//
waitwhilethegadgetisbusy:
gadget-data=data;
gadget-command=
command;
147
Anotheruseforvolatileissignalhandlers.Ifyouhavecodelikethis:
volatile的另一个用途是信号处理程序。
如果你有这样的代码:
quit=0;
while(!
quit)/*verysmallloopwhichiscompletelyvisibletothecompiler*/
Thecompilerisallowedtonoticetheloopbodydoesnottouchthequitvariableand
convertthelooptoawhile(true)loop.Evenifthequitvariableissetonthesignalhandler
forSIGINTandSIGTERM;
thecompilerhasnowaytoknowthat.
编译器可以注意到循环主体不触及quit变量,并将循环转换为while(true)循环。
纵然在信号处理器上为SIGINT和SIGTERM设置了quit变量;
编译器无法知道这一
点。
However,ifthequitvariableisdeclaredvolatile,thecompilerisforcedtoloaditevery
time,becauseitcanbemodifiedelsewhere.Thisisexactlywhatyouwantinthissituation.
但是,如果quit变量被声明为volatile,编译器将被迫每次加载它,因为它可以在
其他地方进行修改。
这正是你在这种情况下想要的。
122
volatileinCactuallycameintoexistenceforthepurposeofnotcachingthevaluesof
thevariableautomatically.Itwilltellthemachinenottocachethevalueofthisvariable.
Soitwilltakethevalueofthegivenvolatilevariablefromthemainmemoryeverytimeit
encountersit.Thismechanismisusedbecauseatanytimethevaluecanbemodifiedby
theOSoranyinterrupt.Sousingvolatilewillhelpusaccessingthevalueafreshevery
time.
实际上,在C中出现volatile是为了不自动缓存变量的值。
它将告诉机器不要缓
存这个变量的值。
因此每次它遇到主存储器时,它都会从主存储器中取出给定的可
变变量的值。
之因此使用这种机制,是因为在任何时候,操作系统或任何中断都可
以修改该值。
因此,使用volatile将帮助我们每次重新访问该值。
53
volatiletellsthecompilerthatyourvariablemaybechangedbyothermeans,thanthe
codethatisaccessingit.e.g.,itmaybeaI/O-mappedmemorylocation.Ifthisisnot
specifiedinsuchcases,somevariableaccessescanbeoptimised,e.g.,itscontentscanbe
heldinaregister,andthememorylocationnotreadbackinagain.
volatile告诉编译器,与访问变量的代码相比,您的变量可以通过其他方式进行更
改。
例如,它可能是一个I/o映射的内存位置。
如果在这种情况下没有指定此选
项,则可以优化一些变量访问,例如,它的内容可以在寄存器中保存,而内存位置
不会再次读取。
24
SeethisarticlebyAndreiAlexandrescu,“volatile-MultithreadedProgrammer’sBest
Friend”
请参阅安德烈·
亚历山大斯库的这篇文章,“volatile—多线程程序员最好的朋友”
Thevolatilekeywordwasdevisedtopreventcompileroptimizationsthatmight
rendercodeincorrectinthepresenceofcertainasynchronousevents.Forexample,ifyou
declareaprimitivevariableasvolatile,thecompilerisnotpermittedtocacheitina
register--acommonoptimizationthatwouldbedisastrousifthatvariablewereshared
amongmultiplethreads.Sothegeneralruleis,ifyouhavevariablesofprimitivetypethat
mustbesharedamongmultiplethreads,declarethosevariablesvolatile.Butyoucan
actuallydoalotmorewiththiskeyword:
youcanuseittocatchcodethatisnotthread
safe,andyoucandosoatcompiletime.Thisarticleshowshowitisdone;
thesolution
involvesasimplesmartpointerthatalsomakesiteasytoserializecriticalsectionsofcode.
volatile关键字被设计用来防止编译器优化,在某些异步事件出现时可能导致代码
不正确。
例如,如果将原始变量声明为volatile,则不允许编译器将其缓存到寄存器
中——如果在多个线程之间共享该变量,这种常见的优化将是灾难性的。
一般的规
则是,如果你有基本类型的变量必须在多个线程之间共享,那么声明这些变量是可
变的。
但是您实际上可以使用这个关键字做更多的事情:
您可以使用它来捕获不属于
线程安全的代码,并且您可以在编译时这样做。
这篇文章展示了它是如何实现的;
解
决方案包括一个简单的智能指针,它还可以使代码的关键部分更容易序列化。
ThearticleappliestobothCandC++.
本文同时适用于C和c++。
Alsoseethearticle“C++andthePerilsofDouble-CheckedLocking”byScottMeyers
andAndreiAlexandrescu:
还可以参阅斯科特·
迈耶斯(ScottMeyers)和安德烈·
亚历山大斯库(Andrei亚历山大)
的文章《c++和双重检查锁定的危险》(c++andthedangerofdoublecheck-locked):
Sowhendealingwithsomememorylocations(e.g.memorymappedportsormemory
referencedbyISRs[InterruptServiceRoutines]),someoptimizationsmustbe
suspended.volatileexistsforspecifyingspecialtreatmentforsuchlocations,specifically:
(1)thecontentofavolatilevariableis“unstable”(canchangebymeansunknowntothe
compiler),
(2)allwritestovolatiledataare“observable”sotheymustbeexecuted
religiously,and(3)alloperationsonvolatiledataareexecutedinthesequenceinwhich
theyappearinthesourcecode.Thefirsttworulesensureproperreadingandwriting.The
lastoneallowsimplementationofI/Oprotocolsthatmixinputandoutput.Thisis
informallywhatCandC++’svolatileguarantees.
因此,在处理某些内存位置(例如,ISRs[中断服务例程]引用的内存映射端口或内
存)时,必须暂停一些优化。
波动存在指定特殊待遇等地点,具体来说:
(1)一个volatile
变量的内容是“不稳定的”(编译器可以改变通过未知),
(2)挥发性数据的写入是“看得见
的”因此他们必须执行宗教,和(3)执行所有操作波动数据序列中出现在他们的源代
码。
前两个规则确保正确的阅读和写作。
最后一个允许实现混合输入和输出的I/O
协议。
这是C和c++不稳定的保证。
我的简单的解释是:
Insomescenarios,basedonthelogicorcode,thecompilerwilldooptimisationof
variableswhichitthinksdonotchange.Thevolatilekeywordpreventsavariablebeing
optimised.
在某些情况下,基于逻辑或代码,编译器会对它认为不会改变的变量进行优化。
volatile关键字防止优化变量。
Forexample:
例如:
boolusb_interface_flag=0;
while(usb_interface_flag==0)//executelogicforthe
scenariowheretheUSBisn’tconnectedFromtheabovecode,thecompilermaythink
usb_interface_flagisdefinedas0,andthatinthewhileloopitwillbezeroforever.After
optimisation,thecompilerwilltreatitaswhile(true)allthetime,resultinginaninfinite
loop.
从上面的代码中,编译器可能认为usb_interface_flag定义为0,而在while循环
中,它将永远为0。
在优化之后,编译器会一直处理它(true),导致无限循环。
Toavoidthesekindsofscenarios,wedeclaretheflagasvolatile,wearetellingto
compilerthatthisvaluemaybechangedbyanexternalinterfaceorothermoduleof
program,i.e.,pleasedon’toptimiseit.That’stheusecaseforvolatile.
为了避免这种情况,我们将标志声明为volatile,我们告诉编译器这个值可能会被
外部接口或程序的其他模块所改变,例如。
,请不要优化。
这就是volatile的用例。
16
Amarginaluseforvolatileisthefollowing.Sayyouwanttocomputethenumerical
derivativeofafunctionf:
挥发物的边际用途如下。
如果你想计算函数f的数值导数:
doubleder_f(doublex)staticconstdoubleh=1e-3;
return(f(x+h)-f(x))/h;
The
problemisthatx+h-xisgenerallynotequaltohduetoroundofferrors.Thinkaboutit:
whenyousubstractveryclosenumbers,youlosealotofsignificantdigitswhichcanruin
thecomputationofthederivative(think1.00001-1).Apossibleworkaroundcouldbe
问题是x+h-x一般不等于h,这是由于舍入误差造成的。
考虑一下:
当你减去非常
接近的数字时,你会丢失大量的有效数字,这会破坏导数的计算(想想1.00001-1)。
doubleder_f2(doublex)staticconstdoubleh=1e-3;
doublehh=x+h-x;
return(f(x
+hh)-f(x))/hh;
butdependingonyourplatformandcompilerswitches,thesecondline
ofthatfunctionmaybewipedoutbyaaggressivelyoptimizingcompiler.Soyouwrite
instead
但是根据您的平台和编译器的切换,该函数的第二行可能会被一个积极的优化编
译器删除。
因此你写
volatiledoublehh=x+h;
hh-=x;
toforcethecompilertoreadthememorylocation
containinghh,forfeitinganeventualoptimizationopportunity.
强制编译器读取包含hh的内存位置,从而丧失最终的优化机会。
10
Therearetwouses.Thesearespeciallyusedmoreofteninembeddeddevelopment.
有两个用途。
这些在嵌入式开发中特别使用。
Compilerwillnotoptimisethefunctionsthatusesvariablesthataredefinedwith
volatilekeyword
编译器不会优化使用volatile关键字定义的变量的函数
VolatileisusedtoaccessexactmemorylocationsinRAM,ROM,etc...Thisisused
moreoftentocontrolmemory-mappeddevices,accessCPUregistersandlocatespecific
memorylocations.
Volatile用于访问RAM、ROM等中的精确内存位置。
这通常用于控制内存映射设
备、访问CPU寄存器和定位特定的内存位置。
Seeexampleswithassemblylisting.Re:
UsageofC“volatile”KeywordinEmbedded
Development
参见组装清单示例。
Re:
在嵌入式开发中使用C“volatile”关键字
9
I’llmentionanotherscenariowherevolatilesareimportant.
我会提到另一种情况,挥发性很重要。
Supposeyoumemory-mapafileforfasterI/Oandthatfilecanchangebehindthe
scenes(e.g.thefileisnotonyourlocalharddrive,butisinsteadservedoverthenetwork
byanothercomputer).
假设您为更快的I/O内存映射一个文件,该文件可以在幕后更改(例如,该文件不
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- IT 专家 为什么 需要 挥发物