本篇笔记,主要是跟踪taskmain()函数中EventGenerateor::parse(event_file)。本篇主要涉及EventGenerator的构造流程,其中对churnEventGenerator类和ChornObserver类进行分析。下面的图示给出了EventGenerateor::parse()函数的调用流程。
    图中EventGenerateor::parse()的调用很简单,首先读取eventfile 里面关于eventgenerator和observer的名字。生成了一个generator实例,然后通过thread()把对应的eventgenerator的任务个激活。最后再生成observer实例。这里我分析了ChurnEventGenerator 和ChurnObserver两个类。按照我的理解Generator主要用于生成对应protocol的node的初始化事件,比如node什么时候开始活过来,以及对eventqueue类实例化和进行激活等操作。observer 的设计本意是用来统计和记录仿真中的各个事件。在P2Psim的设计中,observer的实例化中,observer把自己注册到各个node对象中,这样每次node发消息的时候,在消息队列处理消息的时候,都会把这个消息上的observer拿出来,调用一下他们的kick()来修改observer中的统计信息。
   图中,首先EventGenerator::parse()调用工厂模式生成了eventgenerator实例。我们以churnEventGenerator为例。churnEventGenerator在构造对象的时候,首先读取了所需的参数。图中列出了所有参数,这些参数的具体用途以后再分析(目前我也不清楚,呵呵)。然后实例化了消息队列,并把自己注册为消息队列的observer,这是一个特殊的observer(具体的用途目前也不清楚,估计是每次消息队列处理消息的时候,都能被调用一次)。
  在消息队列的实例化中,消息队列eventqueue,建立了一个特别的channel,然后就调用自己的thread()触发了run()函数变成一个并发任务。run函数首先会在这个channel上等待一个go消息(这个消息会由eventGenerator的实例触发,见图中黄绿色箭头),当收到这个go消息,run()就循环调用advance()函数来处理消息队列里面的每个消息。在处理每个消息的时候,每个消息上的observer会被kick()一下,然后消息队列会执行event上的execute()函数来处理这个消息对应的事务。
      在EventGenerator::parse()生成eventgenerator后,第二件事情是调用了这个实例(churnEventGenerator为例)的thread函数,然后这个消息发生器对象就开始作为一个并发任务开始运行其run()函数了。在其run()函数中,我们可以看到generator的主要工作了:首先生成了一个仿真结束消息,然后从network实例中要来了所有的node信息,把他们都维护在本地的数据结构里面,并把wellknown结点告诉他们,这样他们一开始就能知道他们到那里去找access point。然后设置每个node加入p2p网络的事件。当然,wellknown结点是最早加入的(不然别人找不到他了)。最后给eventqueue发一个go消息,eventqueue就开始处理消息了,整个仿真就开始了(但是由于没有调用yield(),当前任务还没进行切换,所以在物理上那些任务一个都跑不起来)。
    再回到EventGenerator::parse(event_file)函数,最后一步是通过工厂模式建立了observer对象实例。以churnObserver为例,他的工作也很简单,从Network对象实例里面得到所有的node信息,把自己的指针加入他们,这样他们发送消息在消息队列处理时observer就会被触发了。
总结: eventGenerator 是注册在eventQueue上的observer,而普通observer是注册在node上的。
P2Psim分析笔记(5)-EventGenerator and Observer_第1张图片