call_out()函数小结

转:(我也不知道哪年从internat上 copy save下来的)

因为reallove的帖子,我算是第一次较为仔细的看了一遍call_out()在driver中的机理,也明确了不少以前似是而非的概念。现整理如下:

1. 关于call_out()的driver级宏开关有两个(均在options.h当中):

a. THIS_PLAYER_IN_CALL_OUT

该宏被define时,我们可以在被延时呼叫的函数中肆无忌惮的使用this_player()来找到call_out定义时的this_player(),反之则无法找到准确的this_player()(也就是说,可能找到一个谁,但这个“谁”应该与定义call_out时的“谁”毫无瓜葛,肯定不是我们希望的那一个就对了)

b. CALLOUT_HANDLES

该宏被定义时,call_out()原型变成了 int call_out(function foo,int delay, ..),返回值是该call_out的唯一句柄,我们可以在remove_call_out()时以此为参数清理掉“这一个”而非“这一类”call_outs

2. 关于call_out的作用时机和delay的详细含义:

已知call_out记录是以链表与delay的某个余数分类的形式进行存储的。

call_out会在每个系统心跳(不是每个人的心跳,而是说,系统每次呼叫完所有心跳)之后进入对call_out们的处理(仔细的说,driver中call_out.c中的call_out()函数就是干这个事情的)。

因此,就我现在阅读driver代码得到的结论,可以确定的说,call_out一定在心跳点上发作,但会有累积发作的模式。

在解释delay之前,有几个“时间”需要说明:

a. heart_beat()的发作时间:driver通过一个alarm/singal事件来设置hb的标志位,并在backend()的大循环当中不停检查该标志位的状态以决定是否应该触发hb,因此通常可以认为hb的发作较为准确。虽然从代码中看,在不同系统下的编译中,driver使用了alarm和ualarm两种不同方式进行按秒或按微秒级别的触发事件,但不那么精确的描述下,还是可以认为心跳的准时程度较高,更接近与真实系统时间。

b. call_out被插入和判断是否被执行(注意不是是否进入call_out执行过程,而是进入后的“判断”),依据的是另外一个时间标记current_time。该标记在系统启动的时候被设置为当前时间的秒数(unix_time,也就是我们常看到的1239xxxxxxxx这种),其后只在系统心跳时被重置为“当前”。因此这个时间标并不总是等于真实的时间。特别是在hb大于1秒的情况下,如果以真实的秒为ticker来审视它,可能会是:0,0,0,[1,2,3],3,3,3,[4,5,6]这样的情况,即很多秒不变化,然后在同一个时间点上依次++直到追上真实时间。

于是,关于delay有如下看法:

a.在插入一条新的call_out时,delay看起来是从“现在”加上delay秒数后执行被呼叫函数,但这个“现在”是current_time指定的现在,hb>1sec时,他通常指的是过去。。。,因此当我们call_out(foo,3)的时候,他不一定指的是现在+3秒,而是指time()+3秒,他也不一定真的在三秒后执行。不考虑毫秒位的话,通常只有hb为1秒的时候,上面的描述才较为精确。但另外一个方面,delay的含义更倾向于秒,而不是hb。。。(我觉得我已经无法用人类的语言解释清楚这个破玩意儿了。。。。)

b.如前述,call_out被执行一定是在hb的执行点上,具体的执行方式是:在某个HB执行点上,系统扫描小于current_time的call_out记录,然后依次执行(链表的原因,对于应该在“同一个时间点被执行的callout”,先入先执行)。然后系统对current_time++,继续上一步操作,知道current_time追赶上“现在”。

所以说,如果你期望call_out表现比较正常,那最好把hb设为1秒(1000000微秒);否则hb越大,callout的表现就越奇怪。hb非整秒数则会带来其他更微妙的改变。。。。

最后,关于call_out(foo,0)这个特例。

一般来说,我们无法期待这个东西立刻执行。他可能会在下一次hb的时候才被执行。

之所以用“可能”,是因为这个特例还有个更奇怪的特例。该call_out本身处于另外一个call_out的呼叫函数当中。因此这个call_out进行的记录插入动作本身就是在call_out执行点上。可想而知,他立刻就被执行了!!!

我们举两个例子来说明吧:

我们假设hb是10个seconds。查看这样一段函数:

void test()

{

call_out("test_callout",0);

}

void test_callout()

{

tell_object(this_object(),sprintf("CO:%d\n",time()));

call_out("test_callout",0);

}

当我们以某种形式执行了test()的时候,会出现什么状况呢?

首先是test()中的:call_out("test_callout",0)被执行,插入了一条记录,这个记录应当被触发的时间点是current_time+0。(我们假设current_time是333秒吧)

但考虑到hb点还没到。这个时候我们什么都看不到。

等到下一个hb点,也许作为现实时间,是337秒的时候吧(举例)。

上次插入的callout被执行了!

因此我们收到一条CO:333的显示信息(因为current_time这个时候还没++完呢)

接下来就坏掉了,因为又一个call_out("test_callout",0)被执行了!

要注意,这一条call_out插入的触发时间点依然是current_time+0,也就是333。

这时这个test_callout函数被执行完,退出,回到系统的call_out执行循环当中。

坏掉了,系统发现在333这个时间点上还有个未处理的记录(刚插进去的。。)

于是进入了死循环。。。

我们会看到系统不断刷屏CO:333

CO:333

CO:333

CO:333

。。。。

死循环下去了。

上面这个例子表明,callout 0是否立刻被执行,要看他所处的环境,不能一概而论,即时hb是1也如此。

再来一个例子:

同样hb是10seconds。

void test()

{

call_out("test_callout",0);

}

void test_callout(){

tell_object(this_object(),sprintf("CO:%d\n",time()));        call_out("test_callout",1);

}差别是后一个call_out的delay是1。

不详细描述了,我们得到的结果应该是类似:

系统等待发呆。。。。一次性刷屏:

CO:333

CO:334

CO:335

CO:336

CO:337

继续等待发呆个10秒。。。一次性刷屏:

CO:338

CO:339

CO:340

CO:341

CO:342

CO:343

CO:344

CO:345

CO:346

CO:347

等待。。。刷屏。。。等待。。。刷屏。。。。

【mud】call_out()函数相关推荐

  1. 【mud】item_desc之自定义的函数教程(piggy.c例子解析)

    一.函数头部声明 string display_table(string cond); string look_table(); string read_rules(); string look_ha ...

  2. 【mud】npc对话函数与自动对话匹配(gongsun.c)

    //weiqi...97/12/11 inherit NPC; string apply_dancer(object me); string answer_leaving(object me); in ...

  3. 【mud】进场景自动对话函数(clubpoem.c)

    声明 void do_test(); 调用 void create () {   set ("short", "七楼:乐府诗社");   set (" ...

  4. 【转】MUD教程--巫师入门教程4

    我们再次复习一下clean_up()函数返回1的含义,如果clean_up()函数返回1,则MUDOS在这一次的调用时不会做其的任何举动,但到了下一次想调用的时间里,还将再次调用这个对象的clean_ ...

  5. MUD教程--巫师入门教程3

    1. 指令格式为:edit <档名>,只加文件名,默认为当前目录,加here,表示编辑你当前所处的房间, 回车后即进入线上编辑系统.  2. 如果这是一个已经有的档案,你可以使用 z 或 ...

  6. 【转】MUD教程--巫师入门教程2

    简单的人物原则上只要有 set_name<名字> . combat_exp <经验>就行了,当然我们总得稍微多添一点了. inherit NPC; void create() ...

  7. 【转】MUD教程--巫师入门教程1

    <新巫师入门手册> 第一章:观念篇 ■ 内容提要:什么是巫师?怎样做一个巫师?如何做好一个巫师? 第二章:上手篇 ■ 内容提要:最简单的房间怎么写?NPC又怎么写?先看懂一些常用的参数? ...

  8. 从零开始构建PHP版mud游戏(二)

    为什么是mud? 98 99年的时候,我在大学里接触到的第1款网络游戏就是mud,那时候玩的是西游记,可以说mud对我们来说是一种情怀. 到了2020年,为什么我还要选mud? 我想要做一个世界,目的 ...

  9. socket函数简介

    什么是 socket? 他是使用 Unix 文件描述符 (file descriptor) 和其他程序通讯的方式.你也许听到一些 Unix 高手 (hacker) 这样说:"呀,Unix 中 ...

最新文章

  1. Perforce使用之创建DEPOT流程
  2. OpenCV GPU 简单遍历图像
  3. Python 项目实践三(Web应用程序)第四篇
  4. 计算机二级网址打不开,大神为你解决win7系统打不开二级网页链接的操作教程...
  5. 链接数据库增删改通用
  6. mysql批量导入数据脚本_MySQL数据库批量导入脚本
  7. 万物皆可爬系列使用python爬阴阳师图片
  8. java兔子问题流程图_C语言编程狼追兔子问题代码解析
  9. 如何开发与设计一个爆款小游戏
  10. python解析json传入变量_Python 使用 docopt 解析json参数文件过程讲解
  11. C#窗体控件简介ListBox
  12. ib网卡命令_InfiniBand 网卡测试
  13. GCC详解-Binutils工具之c++filt
  14. 金山毒霸系统清理专家
  15. 【信息系统项目管理师】第二十一章 项目组合管理(考点汇总篇)
  16. Echarts的x,y网格线样式
  17. 基于matlab测量物体直径,基于MATLAB的零件尺寸检测误差分析的软件设计
  18. [solved] login to server failed: EOF
  19. Google Alerts 使用指南 | 这个服务,帮你知道互联网上你想知道的各种事
  20. 电子行业数字工厂管理系统有哪些优点和不足

热门文章

  1. SD卡内存卡修复工具哪个好?4款工具对比测评
  2. ValueError: n_splits=n cannot be greater than the number of members in each class.
  3. 华硕FL8000U拆换机械硬盘
  4. 单自由度振动系统 matlab,单自由度系统的振动及matlab分析
  5. SpringCloud微服务架构学习
  6. PHP阅读文章送积分规则代码,php实现微信公众号文章付费阅读功能的代码分享
  7. [UE] 在虚幻中使用动画序列和分层骨骼混合简单实现角色看向
  8. Android 11 正式版发布
  9. 圈的ramsey数研究
  10. Sublime Text的使用代码块安装的模块