设为首页 收藏本站
查看: 1105|回复: 0

[经验分享] 计算机仿真中的HLA技术中的餐馆例子分析 (1) Production

[复制链接]

尚未签到

发表于 2015-11-26 09:14:17 | 显示全部楼层 |阅读模式
  从书中例子来看,这个餐馆例子是第一个真正意义上的仿真例子。因为前两个例子的共同点是:所有联邦都运行同一个程序,仅仅是通过运行设置(比如有的订阅,有的发布),才表现为不同的联邦。而餐馆联邦直接把联邦的程序分开,不同的联邦成员具有不同的程序代码。
  
  另一个方面,书上对这个例子有较详细的解释。这也为这个例子的分析带来了很多便利。
  
  书上把production联邦作为例子进行了详细分析,我们这边也先从production联邦入手。其实后面可以看到,production,transport,comsumption三个联邦代码非常类似,甚至manager和viewer的代码也类似,只是pruduction联邦,consumption联邦使用了NER的时间调度方式,后manager,viewer和transport联邦使用了TAR的时间调度方式。
  
  总体来看,每个联邦都有几个java文件组成,以production联邦为例:Production.java,ProductionFrame.java, ProductionInternalError.java, ProductionNames.java,FedAmbImpl.java(production)。其中,frame是GUI类,FedAmbImpl包括所有回调函数。所有对RTI的函数调用,都在Production.java完成,使用_rti变量。
  --------------------------------------------------------------------------------------------------------
  主函数很简单
  
  public static void main(String[] args) {
    Properties props = parseArgs(args);
  loadProperties(props);
  Production production = new Production(props);
  production.mainThread();
  }
  主要功能是从命令行或者配置文件中读取相关参数,产生production对象,运行mainThread线程
  ---------------------------------------------------------------------------------------------------------
  
  主要的功能都在mainThread函数中
  
  (1)取得相关配置信息,判断是否有federation execution实例运行,没有则创建,然后加入join
  
  (2)设置时间受限和时间调节。这里首先设置了时间受限,同时在设置时间受限和时间调节时,使用了barrier机制来协调各个线程(barrier机制在例子中多次使用,这里不讨论其细节)。
  
  (3)获取相关对象类,属性,交互类的handle,存储下来以备后续使用。--getHandles();
  
  (4)发布对象类及其相关属性,包括Serving类及其position属性和type属性;Chef对象类及其position,chefStage和servingName
  
  (5)订阅对象类及其相关属性,包括Boat对象类及其position,spaceAvailable和cargo属性,以及SimulationEnds交互类和TransferAccepted交互类。
  
  (6)处理第一个同步点ReadyToPolulate,发出同步点已经achieved请求。使用barrier机制阻塞线程,结束阻塞后输出已经同步信息。
  
  (7)根据预先给定的chef个数,逐个注册chef对象实例,并把所注册的chef实例加入本地表格_chefTable中。同时,把每个chef的信息进行更新_rti.updateAttributeValues(chefHandle, sa, null, sendTime);然后随机产生一个类型的sushi,并把该sushi加入_internalQueue--_internalQueue.enqueue(new FinishMakingSushiEvent(eventTime, serial, type));(注意这里,eventTime从0.0开始,每一次增加的时间量是做某种sushi的时间)。 注意,上述所有活动都在循环体内。也就是说,对每个chef,都要做后续的所有工作。同时还要注意,制作不同的sushi的时间不同,但是_internalQueue.enqueue方法将保证制作时间越短的sushi越排在前面。这里的物理含义是:6个chef一起(从_logicTime=0.0时刻)做sushi,则制作时间越短的sushi越早制作好。
  
  (8)处理第二个同步点ReadyToRun,发出同步点已经achieved请求。使用barrier机制阻塞线程,结束阻塞后输出已经在该同步点同步的信息。
  
  (9)调用rti函数enableAsynchronousDelivery,目的是instructs the LRC to begin delivering receive-ordered events to the federate even while no time-advancement service is in progress,其实就是production这个时间受限联邦成员要求在时间批准状态下也能接收RO事件。
  
  (10)进入时间推进的主循环。循环结束条件是该联邦收到simulationEnds交互。基本的消息循环流程:production联邦收到的所有RTI的回调都会进入callbackQueue排队。然后在消息循环里面逐一取出消息来处理。
  
  下面是主循环代码:
  timeLoop:
  while (!_simulationEndsReceived) {
  _userInterface.setTimeStateAdvancing();
  LogicalTime timeToMoveTo = _internalQueue.getTimeAtHead();
  //_userInterface.post("NER to " + timeToMoveTo);
  _rti.nextEventRequest(timeToMoveTo);
  boolean wasTimeAdvanceGrant;
  do {
  Callback callback = _callbackQueue.dequeue();
  wasTimeAdvanceGrant = callback.dispatch();
  if (_simulationEndsReceived) break timeLoop;
  } while (!wasTimeAdvanceGrant);
  updateInternalStateAtNewTime();  
  }
  主循环流程解释如下:
  
  
  while(没有收到simulationEnds交互)
  {
  界面显示联邦开始时间推进;
  从_internalQueue队列中取出队头事件所包含的时间(对production联邦而言,开始运行时,internalQueue中存储的其实就是从0.0时刻开始制作完成的第一个sushi的时间);
  请求时间推进NER到上一条语句所取出的时间上,对production联邦而言,其实就是取出做完一个sushi后的logicTime时间。
  do{
  从callbackQueue中取出一个事件,返回给callback对象;
  调用callback对象的dispatch函数,返回一个布尔量wasTimeAdvanceGrant
  判断是否收到_simulationEnds交互,如果收到,退出循环;
  while (!wasTimeAdvanceGrant);
  从internalQueue中取出所有小于等于当前时间的事件处理掉,此例中就是取出最短时间做好的sushi,注册serving对象实例,并把serving对象实例加入_serving结构中;
  根据当前_chefTable中所有的chef信息发送updateAttributeValues请求;
  根据当前_serving中所有的sushi信息,发送updateAttributeValues请求;
  }        
  
  
  (11)处理第三个同步点ReadyToResign,发出同步点已经achieved请求。使用barrier机制阻塞线程,结束阻塞后输出已经在该同步点同步的信息。然后结束该联邦的运行。
  ---------------------------------------------------------------------------------------------------------------------------
  下面是运行5个联邦后,production.java输出的一些信息以及对这些输出的解释:
  
  
  RTIambassador created
  Federation execution restaurant_1 already exists.
  Joined as federate 8
  Enabling time constraint...
  ...constraint enabled at time<0.0>
  Enabling time regulation...
  ...regulation enabled at time<0.0>
  This point is after subscribe...
  Waiting for ReadyToPopulate...
  �5.10)startRegistrationForObjectClass:3
  �5.10)startRegistrationForObjectClass:6
  ...federation synchronized.
  type0  increase by  interval<1.5>    //这里是产生的6个sushi实例,信息包括type和制作时间,其实意思是说6个chef每人做一个
  type0  increase by  interval<1.5>
  type3  increase by  interval<4.0>
  type1  increase by  interval<2.3>
  type3  increase by  interval<4.0>
  type1  increase by  interval<2.3>
  Waiting for ReadyToRun...
  ...federation synchronized.
  NER to time<1.5>                           //进入主循环,首先根据第一个sushi制作完成的时间,发出NER to 1.5的时间推进请求
  Discovered Boat 115(B_9_0)         //此时,外部事件callback队列中首先出现的时间是tranport.java联邦注册的Boat对象,一共8个。这里callback应该是DiscoverObjectInstanceCallback
  Discovered Boat 117(B_9_1)
  Discovered Boat 118(B_9_2)
  Discovered Boat 119(B_9_3)
  Discovered Boat 120(B_9_4)
  Discovered Boat 121(B_9_5)
  Discovered Boat 122(B_9_6)
  Discovered Boat 123(B_9_7)
  ...granted to time<0.01>              //下一个外部事件队列中出现的是一个time grant
  NER to time<1.5>                         //重新回到主循环的起始,因为得到的time grant的时间小于第一个sushi制作完成的时间,内部事件队列中并不删除第一个sushi制作完成这个事件,重新发出NER to 1.5的时间推进请求
  ...granted to time<1.01>             //又得到一个外部事件队列事件,是一个time grant
  NER to time<1.5>                        //同理,又发出一个NER to 1.5的时间推进请求  
  ...granted to time<1.5>              //这回,终于得到grant了
  Dequeued internal event at time<1.5>, chef: 0   //下面就是从_internalQueue中取出两个1.5时间做好的sushi,注册相应的对象实例,并从_internalQueue中删除两个1.5时间做好的sushi
  This is dispatch in FinishMakingSushiEvent
  Dequeued internal event at time<1.5>, chef: 1
  This is dispatch in FinishMakingSushiEvent
  NER to time<2.3>                      //这回,轮到第三个被做好的sushi了
  Chef 1 attempting to load boat B_9_1  //下一个外部事件是reflectiveAttributeValues,是transport联邦对Boat实例对象属性的修改更新导致的事件
  AODN Serving S_8_1                 //再下一个外部事件是AODN callback,即AttributeOwnershipDivestitureNotificationCallback,RTI回调这个服务通知所有权正式转移
  ...granted to time<2.01>          //下一个外部事件是一个time grant
  NER to time<2.3>                     //没有得到了2.3的grant,继续NER to time 2.3
  ...granted to time<2.3>           //终于得到2.3的grant了
  Dequeued internal event at time<2.3>, chef: 3    //下面就是从_internalQueue中取出两个2.3时间做好的sushi,注册相应的对象实例,并从_internalQueue中删除两个2.3时间做好的sushi
  This is dispatch in FinishMakingSushiEvent
  Dequeued internal event at time<2.3>, chef: 5
  This is dispatch in FinishMakingSushiEvent
  NER to time<4.0>                    //重新回到循环的起始,取出下一个做好的sushi的时间是4.0
  TransferAccepted: S_8_1 from chef serial 1 time<3.01>   //下一个事件是接收到一个交互,
  ...granted to time<3.01>
  NER to time<4.0>
  ...granted to time<4.0>
  Dequeued internal event at time<4.0>, chef: 2
  This is dispatch in FinishMakingSushiEvent
  Dequeued internal event at time<4.0>, chef: 4
  This is dispatch in FinishMakingSushiEvent
  
  ---------------------------------------------------------------------------------------------------------------------------
  
  需要注意的是,callback是一个抽象类,dispatch方法也是一个抽象方法。具体从外部事件队列中取出的事件,调用其dispatch方法时,会根据具体的对象实例所属的类(比如ExternalEvent ,AODNcallback,DiscoverObjectInstanceCallback,ProvideAttributeValueUpdateCallback,ReceiveInteractionCallback,ReflectAttributeValuesEvent,RemoveObjectInstanceEvent,RAORcallback)调用合适的方法。
  ----------------------------------------------------------------------------------------------------------------------------
  
  前面例子中,我们初始时(0.0时间起)一共生产了6个sushi,分别由6个chef生产。现在的问题是:从动态运行的输出来看,当production联邦的时间已经进展到4.0时,所有6个sushi都已经生产出来。则下一个sushi什么时候产生呢? 从源代码查看得知,应该是transport联邦发出TransferAccepted交互时产生了新的sushi。
  
  在production.java中,类public final class ReceiveInteractionEvent extends ExternalEvent是来处理TransferAccepted交互的。即production收到TransferAccepted交互时,将调用上述类中的dispatch方法,而在dispatch方法中,有如下代码:
  
  //put event on internal queue
  LogicalTime eventTime = new LogicalTimeDouble(0.0);
  eventTime.setTo(_logicalTime);
  eventTime.increaseBy(_manufactureTimes[type]);
  _internalQueue.enqueue(new FinishMakingSushiEvent(eventTime, chefSerial, type));
  
  
  显然,上述代码就是产生新的内部事件,该事件说明生产新的sushi,该sushi的开始生产时间是_logicalTime,结束时间是某种sushi生产的时间+_logicalTime
  
  
  对评论的回复:
  
    在下载的book-update-2000-07目录下,有两个批处理,一个是rti运行的批处理,一个是对production联邦运行建立了一个批处理
  rti运行:
  java -cp bin;lib/prti.jar;lib/jgl3.1.0.jar se.pitch.prti.RTIexec
  production联邦运行:
  java -cp src;lib/prti.jar;lib/jgl3.1.0.jar;lib/swingall.jar org.mitre.hla.book.restaurant.production.Production
  之前需要设置java系统的运行目录到path环境变量中,或者jre的bin目录到path中。

  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-143713-1-1.html 上篇帖子: vagrant 下篇帖子: amay's notes for 1.4(SCJP经典笔记)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表