露版权之争未最后达成协议| 《痞子英雄| 库珀版造型成绝唱| 6月男人看球女人看片| 央视8套将播| 蔡少芬首演“嬷嬷| 2012韩国小姐大赛黑幕疑曝光| 雨神四娘分不清楚| 陈奕迅谈与何韵诗激吻| 广受好评| 林志颖关键部位被Kimi玩具偷袭| 演百老汇巨星| 井柏然手写文字感恩粉丝| 清纯好似学生妹| 王凯全家福曝光| 毫不知情| 重返乐坛| 古董车| 卢卡斯炮轰制片人中心制| 2013奥斯卡颁奖夜锁定2月24日| 邓伦郑秀晶上演中韩跨国恋| 英国综艺节目再破尺度| 黄晓明baby大婚白百何不去了| 女星起诉王思聪诽谤| 网友赞率真(图)| 女方否认炒作| 徐子淇晒全家福| 张惠妹为其做动画打气| 杨子姗“西装攻造型帅出新高度| 仅10%电影真正赚钱| 杨千嬅大肚出席| 从楚国贵女到屈原夫人| 自星星的你| 李晨首当监制| 曝八爷郑嘉颖求婚成功| 华妃晒护肤三宝| 否认有第三者望复合| 男星与阿娇传绯闻忙澄清| 宋仲基欧巴要演电影了!依旧还是部战争片,5月开机| 渴望回归|
关闭

关闭

关闭

封号提示

内容

首页 VxWorks_SMP多核编程指南(20110322)

上东庭院北门07年房,急用钱,低价出售!(一口价)

VxWorks_SMP多核编程指南(20110322&#…

爱生活爱胖纸- 2018-10-19 评分 0 浏览量 0 0 0 0 暂无简介 简介 举报
问题二:自动驾驶技术分几个等级?主流看法是可以将自动驾驶的程度分为四个级别,第1级科技含量最少,现在市面上很多能够实现全速自适应巡航、半自动泊车的车辆都可以归类为1级自动驾驶车型。

简介:本文档为《VxWorks_SMP多核编程指南(20110322)doc》,可适用于IT/计算机领域,主题内容包含VxWorksSMP多核编程指南()VxWorksSMP多核编程指南作者:张锴本文摘自vxworkskernelprogrammersguide第章符等。

VxWorksSMP多核编程指南()VxWorksSMP多核编程指南作者:张锴本文摘自vxworkskernelprogrammersguide第章介绍VxWorksSMP是风河公司为VxWorks设计的symmetricmultiprocessing(SMP)系统。它与风河公司的uniporcessor(UP)系统一样具备实时操作系统的特性。本章节介绍了风河VxWorksSMP系统的特点。介绍了VxWorksSMP的配置过程、它与UP编程的区别还有就是如何将UP代码移植为SMP代码。关于VxWorksSMP多核系统指的是一个系统中包含两个或两个以上的处理单元。SMP是多核技巧中的一个它的主要特点是一个OS运行在多个处理单元上并且内存是共享的。另一种多核技巧是asymmetricmultiprocessing(AMP)系统即多个处理单元上运行多个OS。()技术特点关于CPU与处理器的概念在很多计算机相关书籍里有所介绍。但是在此我们仍要对这二者在SMP系统中的区别进行详细说明。CPU:一个CPU通常使用CPUID、物理CPU索引、逻辑CPU索引进行标示。一个CPUID通常由系统固件和硬件决定。物理CPU索引从开始系统从CPU开始启动随着CPU个数的增加物理CPU索引也会增加。逻辑CPU索引指的是OS实例。例如UP系统中逻辑CPU的索引永远是对于一个个CPU的SMP系统而言它的CPU逻辑索引永远是到无论硬件系统中CPU的个数。处理器(processor):是一个包含一个CPU或多个CPU的硅晶体单元。多处理器(multiprocessor):在一个独立的硬件环境中包含两个以上的处理器。单核处理器(uniprocessor):一个包含了一个CPU的硅晶体单元。例如:adualcoreMPCD指的是一个处理器上有两个CPUaquadcoreBroadcom指的是一个处理器上有四个CPU。在SMP系统上运行UP代码总会遇到问题即使将UP代码进行了更新也很难保证代码很好的利用了SMP系统的特性。对于在SMP上运行的代码我们分为两个级别:SMPready:虽然可以正常的运行在SMP系统上但是并没有很充分的利用SMP系统的特点即没有利用到多核处理器的优势SMPoptimized:不仅可以正常的运行在SMP系统上而且还能很好的利用SMP系统的特点使用多个CPU使多个任务可以同时执行CPUAffinity属性。任务级CPUAffinity示例:以下代码说明了创建一个任务并将该任务分配给CPU执行的全过程:【蓝色部分表示调用的关键API】STATUSaffinitySetExample(void){cpusettaffinityinttid*Createthetaskbutonlyactivateitaftersettingitsaffinity*Tid=taskCreate(“myCpuTask”,,,,printf,(int)”myCpuTaskexecutedonCPU!”,,,,,,,,,)if(tid==)returnERROR*CleartheaffinityCPUsetandsetindexforCPU*CPUSETZERO(affinity)CPUSETSET(affinity,)if(taskCpuAffinitySet(tid,affinity)==ERROR){taskDelete(tid)returnERROR}*NowletthetaskrunonCPU*taskActivate(tid)returnOK}下面这个例子是一个任务如何删除它的CPUaffinity:{cpusettaffinityCPUSETZERO(affinity)*passingatidequaltozerocausesanaffinitytobesetforthecallingtask*taskCpuAffinitySet(,affinity)}()中断级CPUAffinitySMP硬件需要可编程中断控制设备。VxWorksSMP利用这些硬件可以分配中断到指定CPU。默认情况下中断是在VxWorks的CPU中触发的。通过中断级CPUAffinity可以将中断合理平均的分配到不同CPU上(而不是在一个CPU上存在很多中断)。运行时刻分配中断到指定CPU是在启动时发生的当系统启动从BSP中读取中断配置信息的时候。然后中断控制器收到一条命令该命令用于指示一条中断运行在指定的CPU上。将CPU预留给使用了CPUAffinity的任务(CPU预留机制)VxWorksSMP提供了一种机制可以将CPU预留给那些已经使用了CPUAffinity的任务。这种机制可以防止其他任务与使用了CPU预留机制的任务抢占CPU资源因此它提升了系统效率。CPU预留机制的API如表所示。表CPU预留机制API描述APISTATUSvxCpuReservedGet(获取可预留CPU的集合cpusett*pCpuSet)STATUSvxCpuReserve(预留CPU集合cpus返回CPU预留的结果cpusettcpus,*CPUstobepReservedCpusreserved*cpusett*pReservedCpus*CPUsreserved*)STATUSvxCpuUnreserve(解除某个CPU的预留机制。cpusettcpus)默认情况下当CPU没有使用vxCpuReserve()时所有CPU都是可以被预留的。可以通过配置VXSMPCPUEXPLICITRESERVE参数将指定CPU排除在CPU预留池之外。只有在CPU池中的CPU才可以被预留。taskCpuAffinitySet()与vxCpuReserve()没有明确的调用顺序。前者是把任务分配给指定的CPU这样可以防止该任务运行在其他CPU上。而后者限定了CPU上可以运行哪些任务。可以根据具体情况分先后调用这两者。【注意】如果一个任务使用了CPUAffinity则它的子任务将会继承CPUAffinity属性如果一个CPU预留给了使用CPUAffinity的任务则这些任务的子任务将会在这个CPU上运行。CPU预留与任务级CPUAffinity的示例以下程序片段展示了如何预留一个CPU以及设置一个任务级CPUaffinity在预留CPU上执行的过程:【蓝色部分表示调用的关键API】voidmyRtn(void){cpusettcpuset*InputargumenttovxCpuReserve()*cpusettresCpuSet*ReturnargumentfromvxCpuReserve()**PassinganemptycpusetasinputreservesanarbitraryCPU*CPUSETZERO(cpuset)if(vxCpuReserve(cpuset,resCpuSet)==OK){*setaffinityforcurrenttask*if(taskCpuAffinitySet(,resCpuSet)!=OK)*handleerror*}else{*handleerror*}}以下代码片段展示了如何预留一个或多个指定CPU并且为多个任务设置CPUaffinity:voidmyRtn(void){externinttids*sometaskIds*intcpuIx={,,}*CPUindicestoreserve*cpusettcpuSetcpusetttmpCpuSetinti*InitializecpuSetwiththedesiredCPUindices*CPUSETZERO(cpuSet)CPUSETSET(cpuSet,cpuIx)CPUSETSET(cpuSet,cpuIx)CPUSETSET(cpuSet,cpuIx)*ReservethespecifiedCPUs*if(vxCpuReserve(cpuSet,)==OK){for(i=i<i){tmpCpuSet=CPUSETFIRSTSET(cpuSet)if(taskCpuAffinitySet(tidsi,tmpCpuSet)!=OK)*handleerror*CPUSETSUB(cpuSet,tmpCpuSet)}}else{*handleerror*}}CPU信息及管理VxWorksSMP提供了一些API和宏定义用于获取及操作CPU的信息。()CPU的信息及管理APIkernelLib和vxCpuLib库提供了用于获取CPU信息以及管理CPU的相关API。kernelLib中的CPUAPI如表所示。表CPU内核信息API描述APIBOOLkernelIsCpuIdle(查看指定CPU是否为空闲状态。返回TRUEunsignedintcpu*CPUtoquerystatus表示CPU为空闲状态。of*)BOOLkernelIsSystemIdle(void)查看所有可用CPU是否为空闲状态。返回TRUE表示为空闲状态。STATUSkernelCpuEnable(通过输入index参数使能CPUunsignedintcpuToEnable*logicalindexofCPUtoenable*)kernelCpuEnable()可以通过输入index参数来使能指定的CPU。一旦CPU使能任务调度机制开始在该CPU上分配任务。所有CPU在默认情况下是使能状态可以将组件ENABLEALLCPUS设置为FALSE这样VxWorksSMP系统启动后只有CPU为使能状态。然后再通过kernelCpuEnable()可以使能指定的CPU。vxCpuLib中的CPUAPI如表所示。表CPU信息API描述APIunsignedintvxCpuConfiguredGet(void)返回在SMP系统中已配置的CPU个数cpusettvxCpuEnabledGet(void)返回使能CPU的个数unsignedintvxCpuIndexGet(void)返回当前CPU的索引(逻辑编号)cpuidtvxCpuIdGet(void)返回当前CPU的ID(有体系结构变量定义的非OS定义的逻辑编号)使用vxCpuConfiguredGet()返回的是配置在BSP中的VxWorksSMP系统的CPU个数。这个值可能与硬件实际存在的CPU个数不一致。使用vxCpuEnabledGet()返回的是系统中运行CPU的个数。这个值可能与vxCpuConfiguredGet()返回的值不一致也可能与硬件中实际存在的CPU个数不一致vxCpuEnabledGet()的返回值类型为cpusett因此我们需要注意:再给返回值赋值之前我们必须使用CPUSETZERO()将cpusett变量清vxCpuIndexGet()返回的是当前调用任务使用的CPU索引(逻辑编号)。该编号在和N之间(N是vxCpuConfiguredGet()的返回值)。需要注意的是:默认情况下任务可以从一个CPU跑到另一个CPU上执行所以不能保证任务结束后所在的CPU索引与刚才使用vxCpuIndexGet()返回的值是一致的。除非该任务是分配运行在指定CPU上的或者使用了taskCpuLock()或者intCpuLock()。()CPU相关变量以及宏定义VxWorksSMP提供了一组变量和宏定义通过设置这些值可以对CPU的配置进行控制。例如cpusett它用于标识配置在VxWorksSMP系统中的CPU。Cpusett的位值标识了CPU的逻辑索引Cpusett的第一位标识了CPU第二位标识了CPU第三位标识了CPU以此类推(它与CPU在硬件中的物理位置无关)。例如有个CPU的硬件系统在BSP中为VxWorksSMP配置了块CPU通过CPUSETZERO()可以讲cpusett中的位值清。调用vxCpuIndexGet()它的返回值只会设置前四位。CPU宏定义用于设置和清除CPU索引(通过改变cpusett的值)。这些宏定义如图所示。表操控CPU信息的宏定义描述APICPUSETSET(cpuset,n)设置CPU的索引(只针对一个CPU进行设置)CPUSETSETALL(cpuset)设置CPU的索引(针对所有CPU进行设置)CPUSETSETALLBUTSELF(cpuset)设置CPU的索引(除了调用该宏的CPU之外的所有CPU)CPUSETCLR(cpuset,n)清除一个指定的CPU索引(只针对一个CPU进行设置)CPUSETZERO(cpuset)清除所有CPU索引(针对所有CPU进行设置)CPUSETISSET(cpuset,n)当指定索引存在于cpusett中时返回TRUE,CPUSETISZERO(cpuset)当cpusett中没有索引时返回TRUE,CPUSETATOMICSET(cpuset,n)原子地设置CPU的索引(只针对一个CPU进行设置)CPUSETATOMICCLR(cpuset,n)原子地清除CPU的索引(只针对一个CPU进行设置)【注意】不要直接对cpusett进行操作而是要通过上面的宏定义间接的对cpusett进行操作。查看任务性能API通过checkStack()可以查看所有任务栈的使用情况。在shell下输入checkStack就可以得到下面的信息。如图所示。图通过checkStack检测任务栈情况SIZE表示任务栈的大小CUR表示当前使用任务栈的大小HIGH表示使用任务栈的峰值MARGIN表示从没有使用过的任务栈大小(其中MARGIN=SIZEHIGH)。通过spy()可以上报任务在内核空间、中断、idle中的tick使用情况。在shell下输入spy就可以得到下面的信息。如图所示。图通过spy查看CPU使用率情况Spy开启了tSpyTask用于监控系统任务的使用情况。IDLE表示空闲任务的CPU占用情况。SMP性能优化SMP的目的就是提高系统的性能。如果仅仅是简单的使用SMP的代码并不能完全发挥出SMP的潜能。因此在SMP代码的基础上还需要进行优化。SMP算法是否能够提高系统性能很大程度上取决于算法并行性的程度以及多线程独立的程度。有些算法是高可并行性的并且很好的利用了多CPU。一个很好的例子:图形压缩器可以在独立的线程中分别压缩一整块数据中的一小块。如果SMP算法不好的话那么同时执行两个线程的消耗将会抵消掉多个CPU所带来的好处。类似的如果存在很多共享数据即多个CPU需要争夺的数据那么系统将会增大争夺、等待数据的消耗。不好的算法会导致更糟糕的情况即SMP系统反而不如UP系统运行的快。最好的情况是使运算速度提高一倍。线程化线程化包括将一个单线程的APP通过任务复制的方式变成多线程。一个典型的例子是:唤醒一个“工人”任务这个任务的工作是从一个队列中获取工作还有一个任务或ISR负责往这个队列中填充工作。假设瓶颈出现在“工人”任务中我们可以通过复制“工人”任务的方式提高系统的性能。线程化不是一个新的概念了在出现多线程OS的时候我们就已经知道这个词了。但是在一个UP系统中线程化只能增加任务的吞吐量即虽然线程增加了但它们却在等待资源。到头来我们发现瓶颈是在CPU本身而线程化并不能提高性能。例如在一个UP系统上计算密集的APP线程化不能帮上什么忙。但是在SMP系统上情况有所不同线程化可以有效地提高系统性能这是因为SMP系统解决了CPU的瓶颈问题。使用Spinlock使用spinlock会潜移默化的影响中断和任务抢占机制。因此必须谨慎的使用spinlock使用的话也必须是在很短的周期内使用和释放。使用浮点数和其他协处理器出于效率的考虑关于使用协处理器的任务创建选项(VPFPTASK)必须被谨慎使用。只有当任务确实需要使用时再添加。当一个任务在创建时开启了协处理器选项时协处理器的状态将被保存同时系统也会保存每一次的上下文切换。这对于那些虽然开启了协处理器但是却没有使用它的任务而言显得没有必要了。使用vmBaseLibvmBaseLib库是VxWorksMMU的管理库它允许内核APP和驱动管理MMU。SMPOS的一个重要任务是保证MMU的后备内存(TLB)的一致性。例如CPUMPCD中有硬件资源可以保证TLB的一致性。其他CPU例如MIPS体系结构家族就没有这个能力。这时候就需要OS进行对MMU一致性的保护了。任务和中断的CPUAffinity对于一些APP和系统分配指定任务或中断到指定CPU上执行可以提高系统的效率。简单例子VxWorksSMP提供了一些测试程序用来测试SMP的特点和性能。以下程序测试了IO功能和系统调用功能:philDemosmpLockDemo以下测试了计算能力:primesDemorawPerf可以通过配置VxWorks内核的方式(添加INCLUDESMPDEMO组件)将这些测试程序链接到VxWorksSMP内核镜像中。测试源代码在installDirvxworksxtargetsrcdemosmp中。在此以installDirvxworksxtargetsrcdemosmpsmpLockDemoc为例来说明关于SMP编程的一些注意事项:*smpLockDemoc用于测试VxWorksSMP的同步互斥机制*描述:*这个demo描述了VxWorksSMP中的同步机制。在SMP系统中任务和ISR可以同时运*行在不同的CPU上这就涉及到同时访问共享数据的问题对此VxWorksSMP提供*了一系列机制:*信号量(Semaphore):可以使用信号量实现任务间的同步机制。例如使用一个任务或*ISR“唤醒”另一个任务。*VxWorks事件(VxWorksEvents):同信号量。*原子操作(AtomicOperator):能够安全的读、写内存。例如完成一些类型的全局的*自增操作。*Spinlock:它可以用在任务间、ISR间、任务与ISR间的同步。它一般用来对较多的共*享数据和临界资源进行保护。**本demo对以上同步机制进行了对比。通过SMP系统中多个任务对一个共享int型变量*操作的实例来对比这些同步机制。**DEMO执行*本demo中包含了两个优先级一样的任务每个任务都重复地(循环)增加一个共享计*数器。这个共享计数器是用户定义的一个累加值(即被更新次数)。每个任务还有一个*自己的计数器在增加共享计数器的同时也增加自己的计数器。假设任务自己的计数器*不会出错我们要看看使用不同同步机制的不同效果即共享数据的值是否与两个任务*自身计数器的值之和一致。**以上过程重复次每次使用不同的同步机制:*不使用同步机制:任务访问共享数据时不使用同步机制。*Spinlock:当任务累加共享数据的时候申请spinlock然后再释放spinlock。*vxAtomicInc()原子操作:任务使用原子操作vxAtomicInc()对这个共享数据进行累加。*vxTas()原子操作:在任务中通过vxTas()设置清除一个flag将这个flag当做一个普*通信号量使用。当这个flag被清除时表示信号量不可用当被设置时表示可用。任务*需要使用这个信号量对共享数据进行累加然后再释放信号量。*vxAtomicAdd()原子操作:在任务中使用vxAtomicAdd()原子操作对共享数据进行累*加。**调用任务*在SHELL中输入smpLockDemo*参数表示任务更新共享数据和自己数据的时长(以秒为单位)。如果不填写参数则*已秒为默认值。**执行结果:*METHODTASKTASKSUM(COUNTS)GLOBALRESULT**nolockxdaexbcxabcaxdFailed*spinLocksxfxaxfdxfdPassed*atomicIncxbdxbxaxaPassed*testandsetxexaxaaxaaPassed*atomicAddxebaxedaxccxccPassed**METHOD栏表示任务为了更新共享数据而使用的同步机制。TASK任务栏表示TASK*自己的计数器值TASK任务栏表示TASK自己的计数器值。计数器的值越大说明*同步机制越好。SUM(COUNTS)栏表示前面两个栏之和(TASK和TASK栏的和)。*GLOBAL栏表示共享数据的值。RESULT栏表示了SUM值是否与GLOBAL的值一致。**从上面的测试结果可以看出不使用同步机制是不行的即使对共享数据仅仅是一个小*小的自增操作不使用同步机制也会造成错误。结果还可以看出使用vxAtomicInc()*原子操作不仅安全而且其效率比vxAtomicAdd()要高而vxAtomicAdd()的效率比使*用Spinlock()要高。原子操作效率高于spinlock的原因在于它们就是为简单原子读写操*作设计的而spinlock则是对相对复杂的同步机制设计的。testandset方法通过使用*vxTas()执行一个信号量这种方法比原子操作慢比spinlock快。但是在数据需要极*端小心操作时还是使用spinlock这种锁机制比较好。Spinlock是普通信号量更安全的*替代品。**下面是同样的程序、同样的周期在一个UP系统上运行的结果。通过结果我们看到这*里没有冲突、没有错误这是因为没有真正意义的同时执行存在。但是从计数的结果*来看性能还是要比前者好的。这是因为由于任务不能同时执行很少有对共享数据*的竞争存在。不过这个例子从另一个方面说明:一个APP虽然有“同时执行”*的能力但是过多的“竞争”使得这种并行的好处大打折扣。**>smpLockDemo*METHODTASKTASKSUM(COUNTS)GLOBALRESULT**nolockxdxeexcdcxcdcPassed*spinLocksxaaexaaefafxdxdPassed*atomicIncxcxcxcdxcdPassed*testandsetxaddxacxbxbPassed*atomicAddxbcxbbxcxcPassed*【注意】在此只对关键部分进行说明因此部分代码就不在写了大家可以查看它的源文件进行对照。【蓝色的是本文介绍的关于SMP的一些API】头文件略LOCALvolatileBOOLlockDemoWorkersReady=FALSELOCALatomicttasVar=*variablefortestandsetmethod**smpLockDemosmpLockDemo入口函数(也是SHELL命令)*>smpLockDemo<numberofsecs>,<numberoftasks>,<TRUE,FALSE(affinity)*这个函数会开启两个任务用于同时更新一个共享数据与此同时更新自己的一个数据。*<secs>参数表示使用不同同步机制进行测试的时间(默认为s)即每种算法会给<secs>*进行测试。*STATUSsmpLockDemo(unsignedintsecs,*Theminimumlifetimeofaworkertask*unsignedintreqNumOfTasks,*numberoftasks*BOOLsetAff*dotaskhaveaffinity*){unsignedintavailCpus=vxCpuConfiguredGet()获取已配置CPU个数unsignedintnumOfTasksunsignedinteventsToWait=LOCKSDEMOTYPElockMethod=methodLockNone这是一个枚举表示不同机制if(reqNumOfTasks==)numOfTasks=availCpuselsenumOfTasks=reqNumOfTasksif(secs==)secs=*Create,setaffinityandactivitedtasks*if(locksDemoTasksInit(secs,numOfTasks,setAff,eventsToWait,lockMethod)!=OK){returnERROR}lockDemoWorkersReady=TRUE*Waituntilallworkertasksaredone*if(eventReceive(eventsToWait,EVENTSWAITALL,WAITFOREVER,)!=OK){returnERROR}}*locksDemoTasksInit初始化、激活、设置CPUAffinity任务。默认情况下任务的*CPUAffinity属性是关闭的。locksDemoTasksInit创建了数个任务。*LOCALSTATUSlocksDemoTasksInit(intsecs,*howlongtorun*unsignedintnumOfTasks,*numberoftasksevolved*BOOLaffIsOn,unsignedint*eventsToWait,*Eventstowaitmask*LOCKSDEMOTYPElockMethod*Methodofglobalcountlock*){cpusetttaskAffinityunsignedinteventWorkerDoneinti=workerTidi=taskIdSelf()workerTid是一个数组用于记录任务IDwhile(i<(numOfTasks)){*Task'snumberisthebittosendaneventon*eventWorkerDone=<<i*AddeventtothereceivelistfortheMaintasksreceives**eventsToWait|=eventWorkerDone*Createthespecifiednumberoftasks*if((workerTidi=taskCreate("worker",WORKERTASKSPRIORITY,,,(FUNCPTR)workerEntry,secs,taskIdSelf(),numOfTasks,eventWorkerDone,i,lockMethod,,,,))==ERROR){returnERROR}**Setaffinityforeachtaskifrequestedandthatnumberoftasks*thenumberofCPU'savailable*if(affIsOn==TRUE){taskAffinity=<<i*Setaffinitythetaskaffinitywiththetaskindex*if(taskCpuAffinitySet(workerTidi,taskAffinity)!=OK){return(ERROR)}}*setAff==TRUE**Activatetask*if(taskActivate(workerTidi)!=OK){return(ERROR)}i*Incrementiteration*}*endwhile*}*workerEntry开启任务的入口。在开启任务之前要确保lockDemoWorkersReady被设置为TRUE这样可以允许所有任务同时开启。***LOCALvoidworkerEntry(intsecs,*thelenghtofdemoduration*intparentTask,*Idofcreatortask*unsignedintnumOfTasks,UINTeventWorkerDone,*uniqueIdtoindicatethistaskisdone*unsignedintthreadNum,*tasksequencenumber*LOCKSDEMOTYPElockMethod*methodusedtolocktheglobalcount*){intstopTick*Don'tstartuntilallworkersareready*while(lockDemoWorkersReady!=TRUE)*starttimeronceeveryoneisready*stopTick=tickGet()sysClkRateGet()*secsFOREVER{*Updateglobalandlocalcount*if(locksDemoGlobalCountOp(lockMethod,threadNum,numOfTasks)!=OK){printf("spinLocksfairnesstestfailed")eventSend(parentTask,eventWorkerDone)break}*Keepincrementingwhilebeforewereachendtime*if(tickGet()>stopTick){*Informthatworkerisdone*eventSend(parentTask,eventWorkerDone)break}*tickGet()>stopTick*}*FOREVER*}*locksDemoGlobalCountOp对一个共享数据和任务的私有数据进行累加。*在这个函数中会根据不同的同步机制进行运算。它有三个参数:第一个参数表示使用*的同步机制第二个参数表示调用该函数的任务ID这个参数用于累加任务私有的数*据第三个参数表示任务个数。本函数会对五种同步机制进行运算。*LOCALSTATUSlocksDemoGlobalCountOp(LOCKSDEMOTYPElockMethod,*Meansofmutualexclusion*unsignedintthreadNum,unsignedintnumOfTasks*Numberoftasks*){*Checkthemethodwearecomputingoperationfor*switch(lockMethod){casemethodTaskSpinLock:{*useafairspinlock*SPINLOCKTASKTAKE(fairTaskSyncLock)*makesurethatweonlytakeafairturn*varsToUpdatethreadNum*Updatemylocalcount*varsToUpdate*incrementsharedcopy*SPINLOCKTASKGIVE(fairTaskSyncLock)*releasethelock*break}casemethodIsrSpinLock:*useaspinlock*SPINLOCKISRTAKE(isrSyncLock)varsToUpdatethreadNum*Updatemylocalcount*varsToUpdate*incrementsharedcopy*SPINLOCKISRGIVE(isrSyncLock)*releasethelock*breakcasemethodIsrNdLock:*useaspinlock*key=spinLockIsrNdTake(isrNdLock)varsToUpdatethreadNum*Updatemylocalcount*varsToUpdate*incrementsharedcopy*spinLockIsrNdGive(isrNdLock,key)*releasethelock*breakcasemethodAtomicInc:varsToUpdatethreadNum*Updatemylocalcount**Atomiccallyincrementglobalcount*vxAtomicInc((atomict*)varsToUpdate)breakcasemethodVxTas:*usetestandset*while((vxTas((void*)tasVar)!=TRUE))varsToUpdatethreadNum*Updatemylocalcount*varsToUpdate*Updateglobalcount*VXMEMBARRIERRW()*preventaboveaccessesfromleaking*vxAtomicSet((atomict*)tasVar,)breakcasemethodVxAtomicAdd:*Updatemylocalcount*varsToUpdatethreadNum*incrementsharedcopy*vxAtomicAdd((atomict*)varsToUpdate,)breakdefault:casemethodLockNone:*updatemylocalcount*varsToUpdatethreadNum*Updatetheglobalcount*varsToUpdate=varsToUpdatebreak}*endSwitch*returnOK}向VxWorksSMP系统移植代码向SMP系统移植代码最关键要考虑的就是对称多处理允许任务与任务间、任务与ISR间、ISR与ISR间可以同时执行。从VxWorksUP向SMP移植代码需要一些步骤。移植的过程需要用到不同的多任务机制还有一些互斥同步机制等等。在移植代码时我们需要将taskLock()替换成spinLockTaskTake()类似的地方还有很多。本大节对代码移植做了总结包括OS设备需要考虑的一些问题还有在移植过程中的一些细节问题等。()代码移植步骤本小节描述了从VxWorksUP向SMP移植APP的模式和推荐步骤。风河推荐:在将早期版本的VxWorksUP代码移植到当前版本的VxWorksSMP时使用如下步骤:a将原来的UP代码移植到当前VxWorksUP系统中把使用VxWorksUPprevious(或更早)系统的代码移植到VxWorksUPcurrent系统中。在这个过程中要将一些API替换成当前版本中支持的API要把一些与VxWorksSMP不兼容或不支持的API替换掉。b将当前VxWorksUP代码移植为当前VxWorksSMP代码把使用VxWorksUPcurrent系统的代码移植到VxWorksSMPcurrent。在这个过程中要注意“同时执行”会引起的一些bug(例如死锁等)。硬件的替换也包含在这个过程中(CPU从UP到SMP)。c为提升SMP性能优化代码对代码进行优化这样可以使程序充分利用对称多处理的优势。代码移植过程如图所示。图UP代码向SMP的移植过程()UP与SMP编程中不兼容的API表列出了UP与SMP编程中不兼容的API和LIB库。在UP代码向SMP代码移植的过程中必须注意替换以下API:表UP与SMP中不兼容的API不兼容的UP的APISMP对应的API备注代码中的隐式同步机制使用显示同步机制例如信号见“任务的隐式同步机制”量或spinlock小节若干cacheLib库函数修改了对应函数的用法见“cacheLib限制”小节若干vmBaseLib库函数修改了对应函数的用法见“vmBaseLib限制”小节taskLock(),intLock()替换为spinLockLib,见“同步与互斥机制”小节taskCpuLock(),intCpuLock(),见“任务锁”小节原子操作taskRtpLock(),替换为信号量、原子操作见“同步与互斥机制”小节taskRtpUnlock()见“RTP中的任务锁”小节任务变量taskVarLib库函数thread存储类见“任务变量管理”小节tlsLIb库函数thread存储类见“任务本地存储”小节访问CPUspecific全局变量替换为CPUspecific全局变见“SMPCPUspecific变量和量访问函数UP全局变量”小节内存访问属性与SMP内存不见“内存访问属性”小节一致不适用VxBus的驱动适用于VxBus的驱动见“驱动与BSP”小节UP的BSPSMP的BSP见“驱动与BSP”小节UP的bootloaderSMP的bootloader()RTP应用与SMP在VxWorksUP系统中RTP(用户模式)应用对于互斥同步机制的限制要比内核代码和内核应用要多。在VxWorksSMP中RTP(用户模式)可以使用信号量、原子操作但不支持spinlock内存障碍以及CPUspecific这些互斥机制。此外使用semExchange()可以实现一个信号量的原子性的give和exchange操作。()任务的隐式同步机制VxWorks是一个支持多任务的OSVxWorks和它的APP是支持可重入的。因此当任务使用显示同步机制的时候当代码移植到一个允许“同时执行”的系统上时需要小心。例如任务A释放了一个信号量给任务B得以使其运行这是一个显示的同步机制。另一方面隐式同步机制通过任务优先级不能在VxWorksSMP中使用。例如如果一个高优先级的任务A生成了一个低优先级的任务B希望在任务A释放CPU之前任务B不能运行这种假设在SMP系统中是不成立的。通过任务优先级实现的隐式同步机制不易被发现需要仔细查阅所有使用了与生成任务相关的代码。例如我们要重点查看使用了下述API的代码:a创建任务的API例如taskSpawn()rtpSpawn()等一些创建新任务的API。在SMP系统中无论新的任务与父任务的优先级谁高谁低新任务可能会在创建任务的API返回后在另一块CPU上运行。如果父任务与子任务使用信号量、消息队列或其他机制进行通信则它们必须在创建新任务之间被创建和被初始化。b会激活一个处于waiting中的pend任务的API例如semGive()msgQSend()eventSend()等一些会激活处于waiting中的pend任务的API即使被激活的任务优先级比调用以上API函数的任务低被激活的任务也有可能在调用函数返回之间开始运行。例如在一个VxWorksUP系统中一个任务可以通过使用intLock()在保护临界资源同时也会屏蔽所有中断以防止ISR访问临界资源。当ISR访问临界资源时不会使用显示互斥机制这是因为当UP系统中运行ISR时任务是不能运行的(驱动会使用很多ISR当任务使用intLock()时这些ISR会排队等待工作)。而在SMP系统中ISR工作的同时任务不工作这种假设是不成立的。因此在ISR中必须使用显示互斥机制。关于ISR的spinlock可参见“spinlock互斥与同步”大节。()同步与互斥机制由于SMP系统中允许真正意义上的“同时执行”存在因此VxWorksUP与VxWorksSMP中的显示同步互斥机制有所不同。信号量在VxWorksUP和VxWorksSMP系统中的用法是相同的。但是关于中断锁和任务锁在两个系统中的用法就是不同的了。例如在VxWorksSMP中一个任务和一个ISR可以同时运行这在VxWorksUP中是不可能的。因此一个任务和ISR之间的互斥机制也就随着系统的变化而变化。任务与ISR之间一个通用的同步机制就是二进制信号量这种机制在VxWorksSMP系统中同样奏效。因此UP代码中使用二进制信号量的地方在VxWorksSMP系统中不用修改。同样的情况也适用于消息队列和VxWorks事件(event)机制。【注意】当一个ISR唤醒了一个任务(可以通过释放一个二进制信号量或发一个事件再或者发送一个消息给一个消息队列等等)该任务必须立即运行在另一个CPU上。()UP中API在SMP中的变异VxWorksUP与VxWorksSMP提供的API大多数是相同的也有一部分在函数行为上是不同的这是因为在SMP系统的需求即它们的使用有一定的限制。cacheLib限制VxWorksUP中的cacheAPI是围绕UP系统设计的。包括:使能、使无效cache清除cache中数据cache天生具有CPUspecific属性它们统统设定为本地CPU的cache。在SMP系统中这种天生的CPUspecific属性变得没有意义。VxWorksSMP支持的系统提供硬件cache一致性这种一致性包括SMP系统CPU之间的也包括内存子系统与设备内存空间之间的。为了实现折现特点下面描述了VxWorksSMP中关于cache限制和行为的改变。cacheEnalbe()和cacheDisable()。能够使硬件cache保持一致性的唯一方法就是使cache一直处于开启状态。因此在VxWorksSMP中每个CPU的cache都要处于使能状态不可以将它们关闭。因此在VxWorksSMP中调用cacheEnable()总会返回OK而调用cacheDisable()总是返回ERROR。ERRNO是ScacheLibFUNCTIONUNSUPPORTEDcacheClear(),CacheFlush()以及cacheInvalidate()为了确保硬件cache一致性这些API不再需要。因此如果在VxWorksSMP中调用这些API它们不会进行任何操作除了返回OK。cacheLock()cacheUnlock()。VxWorksSMP中不支持这些API。如果调用将会返回ERROR,错误码是ScacheLibFUNCTIONUNSUPPORTEDcacheTextUpdate()。该函数在VxWorksSMP中的使用方法与VxWorksUP中相同。vmBaseLib限制VxWorksSMP不提供交换内存页属性的API。在一个SMP系统中RAM空间在CPU之间是共享的。如果系统RAM中的一个单独页属性被修改了以至于它不再是硬件一致性的了任何OS对这个页的操作(例如spinlock、共享数据结构等等)将会产生一个高风险的不可知的后果。这种不可知的行为甚至在页属性改变后许久还能发生。这种情况很难通过debug查到这是因为在SMP中我们都是基于硬件一致性进行工作的。vmBaseStateSet()与vmStateSet()。在UP中这些API用于修改虚拟内存中单独页的属性。在SMP系统中一个页的cache属性不能被修改。调用这些函数都会返回ERROR并且错误码置为SvmLibBADSTATEPARAM()在SMP中不支持的UPAPI以及SMP提供的替代APIVxWorksUP中的一些API在VxWorksSMP中不能使用这是因为VxWorksSMP提供真正意义上的同时执行。VxWorksSMP针对对称多处理特点提供了这些API的替代品。中断锁:intLock()和intUnlock()在VxWorksUP中当一个任务(或ISR)调用了intLock()则它阻止了VxWorks调用其他的中断(即关中断)。这个API典型的用法是保证任务间、任务与ISR间、ISR间对临界资源的互斥访问。这种机制在SMP系统中不再适用VxWorksSMP提供了以下替代的方法:a如果中断锁用来在一块内存上进行虚拟(pseudo)原子操作那么原子操作将是一个好的替代品b如果中断锁用在任务间的互斥机制那么信号量或者任务级spinlock将会是一个好的替代品。Spinlock申请释放的操作要比信号量快因此对于要求性能的、占用时间较短的临界资源时使用spinlock比较合适。而信号量用于保护占用时间较长的临界资源时比较合适c如果中断锁用在任务与ISR间或者ISR间则中断级spinlock比较合适d如果中断锁用在任务间的互斥机制并且所有参与互斥的任务有相同的CPUaffinity那么就可以使用taskCpuLock()e如果中断锁用在任务间、任务与ISR间或者ISR间并且参与互斥的所有任务和ISR有相同的CPUaffinity那么就可以继续使用intCpuLock()。任务锁:taskLock()与taskUnlock()在VxWorksUP系统中当一个任务调用了任务锁API则它会禁止系统中其他任务的调度直到该任务释放了对应的任务锁。这些API的典型用法是保证临街资源的互斥访问。在VxWorksUP中内核APItaskLock()会把任务调度机制挂起。这种机制在SMP系统中不再适用VxWorksSMP提供了以下替代的方法:a信号量b原子操作c任务级spinlock。Spinlock申请释放的操作要比信号量快因此对于要求性能的、占用时间较短的临界资源时使用spinlock比较合适d如果中断锁用在任务间的互斥机制并且所有参与互斥的任务有相同的CPUaffinity那么就可以使用taskCpuLock()。RTP中的任务锁:taskRtpLock()与taskRtpUnlock()在RTPAPP中使用taskRtpLock()使得调用该API的进程不能再调用其他任务。与taskLock()一样taskRtpLock()在SMP中不再适用。在SMP中调用taskRtpLock()会引发致命错误并值得进程终止。可以使用信号量或原子操作替换。任务变量管理:taskVarLibtaskVarLib提供了VxWorksUP中的任务变量设备它不适用在SMP系统中。多个使用相同任务变量的任务可能在同时执行。因此任务变量以及taskVarAdd()和taskVarDelete()函数在VxWorksSMP中不再适用。可以使用thread存储类进行替换。任务本地存储:tlsLibtlsLib为VxWorksUP用户模式的RTPAPP提供了任务本地存储API。但这些API在SMP中不再适用。这是因为使用相同任务变量的多个任务可能在同时执行。这些tlsLib的API包括:tlsKeyCreate(),tlsValueGet(),tlsValueSet(),tlsValueOfTaskGet(),tlsValueOfTaskSet()可以使用thread存储类进行替换。)SMPCPUspecific变量以及UP全局变量(在UP中全局对象中一些(例如errno)在SMP中是属于不同CPU实体的(CPUspecificentity)。而另外一些在SMP中是不可访问或不存在的。SMPCPUspecific变量可以通过对应API间接访问的SMPCPUspecific变量包括:errno,taskIdCurrent,intCnt,isrIdCurrentErrno从一个程序员的角度来看errno就像一个包含了当前运行任务(或ISR)错误码的全局变量。VxWorksSMP可以透明的管理像errno这样的CPUspecific变量。【注意】不要直接访问errno也不要在没有包含errnoh头文件的C或C代码中直接访问errno。taskIdCurrent。在SMP中没有这个全局变量。在SMP中必须使用taskIdSelf()替换UP中的taskIdCurrentintCnt。在SMP中指定中断在指定CPU上运行。intCnt用来跟踪在指定CPU上运行的中断个数。在SMP中要使用intCount()替换UP中的intCnt。isrIdCurrent。它用来标识ISR在指定CPU上运行。只有当INCLUDEISROBJECTS组件添加时这个全局变量才可用。在SMP中必须使用isrIdSefl()替换UP中的isrIdCurrent。仅在UP中出现的全局变量有些全局变量仅在VxWorksUP中存在或者在VxWorksSMP中不能被用户代码访问他们包括:vxIntStackBase,vxIntStackEnd,kernelIsIdle,windPwrOffCpuStatevxIntStackBase该变量标志了中断栈的基地址。在VxWorksSMP中每个CPU有一个vxIntStackBase处理中断这是因为在多个CPU上的中断可能会同时发生。没有API可以访问这个全局变量它不能被用户代码访问。vxIntStackEnd该变量标识了每个CPU中断栈的终止地址。没有API可以访问这个全局变量它不能被用户代码访问。kernelIsIdle在VxWorksUP中该变量用于指出当前系统是否为idle。SMP中没有这个变量。windPwrOffCpuState该变量标识了指定CPU的电源管理状态。没有API可以访问这个全局变量它不能被用户代码访问。()内存访问属性在SMP系统中为了支持内存一致性必须确保每个CPU可以看到一样的内存上下文。根据不同的CPU体系结构一些内存访问属性不能满足内存一致性的需求。()驱动与BSPVxWorksSMP的驱动与BSP开发必须遵从本章叙述的开发规则。驱动还必须符合VxBus驱动模式。BSP为了提供VxBus支持必须提供与VxWorksUP不同的reboot处理机制、CPU列举、中断查找与分配等等

用户评论(0)

0/200

精彩专题

上传我的资料

每篇奖励 +1积分

资料评分:

意见
反馈

立即扫码关注

爱问共享资料微信公众号

返回
顶部

举报
资料

岳云鹏晒术后脸肿缠绷带照 露大内裤 魔术遭金美伦揭穿(图) 吴镇宇自曝性取向 暗示婚变为假新闻 小时候和哥哥关系很差 郭富城因"换鞋论"成公敌 检察厅介入调查 《末日崩塌》 简单生活
晒得像个黑炭 这画面太美 网友赞撞脸(图) 甄子丹小姨子汪圆圆将大婚 黄金阵容打造“真乐闹喜剧片 业内解读七夕档混战 阿甘称其是古代版达人秀 不甘与杨宗纬打平(图) 眼神迷离看远方(图) 同学赞其银幕女神 大S靠谱hold住姐太嫩 遇儿子亲吻险落泪(图) 霸道总裁变国民翠花