sunlock 发表于 2010-11-16 11:46:56

有关Proactor的定时器的问题

本帖最后由 sunlock 于 2010-11-16 12:16 编辑

网上很多关于怎么使用Proactor的定时器,实际上开始用起来比较简单:
从ACE_Handler派生一个定时器类 如Timer:public ACE_Handler,重写这个类的handle_time_out函数,在里面实现自己的定时器处理。
然后用Proactor注册这个派生类的对象,简单的定时器就可以用了。

问题是,删除的的时候有问题:
我怎样删除这个定时器对象呢? 当我删除这个对象的时候(先Canceltimer一下),还有很多没有处理的定时器完成事件,我究竟要等到什么时候删除呢?

另外我怎么觉得 ACE::Proxy不管用,对象自己引用了自己,发异步请求时,靠的就是这个引用,可是当这个对象要销毁的时候,它直接把里面的值赋空

有谁能给讲讲呢

freeeyes 发表于 2010-11-16 14:00:57

关于定时器,我个人并不建议所有的定时器都要和Proactor或者Reactor绑定。毕竟反应器要做的事情很多,有时候过多的定时器会影响程序性能。
所以我建议,定时器你独立拿出来用,ACE有专门独立的定时器,实际上Proactor和Reactor里面也是这样实现的。你启动一个自己的线程。
ACE的定时器池有多种,比如常用的是
#include "ace/Timer_Queue.h"
#include "ace/Timer_Heap.h"
#include "ace/Timer_Wheel.h"
#include "ace/Timer_Hash.h"
#include "ace/Timer_List.h"
这里如果不熟悉的话,你可以看一下这些头文件的注释,写的很清楚。
使用的时候,建议使用比如
typedef ACE_Thread_Timer_Queue_Adapter<ACE_Timer_Heap> ActiveTimer;
ActiveTimer就是你的定时器,你可以调用(比如)
ActiveTimer objActiveTimer;
objActiveTimer.schedule(this, NULL, ACE_Time_Value(MAX_MSG_STARTTIME), ACE_Time_Value(m_u2ThreadTimeCheck));
取消定时器依然,看一下这个类就知道了。
这样你就可以完全不依赖反应器去实现你的定时机制。

sunlock 发表于 2010-11-16 16:26:32

你这也是一种方式。

但如果用了Proactor,Reactor,同时我也使用了线程池,我就不想自己再弄个线程或主动对象来做个独立的定时器了
仔细看了一下2种情况下的 UpCall,reactor下的实现得比较完善,可以调用到定时处理器(我取的名,定时器和定时处理器不是一个东西),Proactor下的upcall都是些空函数,里面注释do nothing。
这另种情况下,定时器不管内部实现如何不同,接口应该给一致吧 现在接口不大一致

我原帖问题的问题是: 我创建了一个定时处理器,然后挂了个定时器,定时器是内部的,咱们看不到。
当我不要定时器的时候,我可以调用cancel来终止这个定时处理器(或者根据定时器的ID)。
问题是,我什么时候删除这个定时处理器呢,没准当我删除了这个定时处理器,它又调用了,因为为通过队列来驱动的。他调用timeout的时候,我没准已经删除了处理器。
即使用锁,你也不知道timeout后面还会不会有timeout,比较费劲。

我在AGP中看到一个cancel定时的例子。 它直接从ACe_Event_Handler派生定时处理器类(用reactor)
然后直接new 一个出来,创建定时器,在要退出时,只是cancel了一下,也没见它删除这个new出来的定时处理器。

不会造成内存泄露?

sunlock 发表于 2010-11-16 17:31:50

仔细跟踪了一下reactor的定时器机制,接口非常完善,如果用定时器首先建议用reactor的。我以上所说的是Proactor的定时器。

reactor的定时器:
在ACE_Event_Handler的timeout的返回值很重要。如果返回值为-1 ,框架会调用handle_close.这个时候可以在这里把new出来的定时处理器给删除delete this。
另外如果不想这样做,可以在cancel的时候将调用close的参数设置成0,这样会触发handle_close的调用。同理可以deletethis了。

另外注意的是:在第一种情况下,即使在timeout返回-1,触发调用handleclose,当再次cancle定时器的时候,还会触发handleclose,这样将有两次调用handleclose,必须避免。

我上面第一帖所说的问题,可能不是定时的问题。而应该是异步请求的问题。
再努力跟跟。

modern 发表于 2010-11-24 11:17:53

对于Reactor,可以直接复用ACE_Event_Handle内部的应用计数。
对于proactor,如楼主所说,Proactor下的upcall都是些空函数,里面注释do nothing。
因此需要自己手工处理一下。
可以用原子变量(ACE_Atomic_op)实现了一个引用计数,初始值为1,
处理时count++,处理完count--,
主动关闭或者连接断开时,主动count--,
判断如果count==0 做清理工作。

maddreamw88 发表于 2010-12-29 17:11:35

回复 2# freeeyes

typedef ACE_Thread_Timer_Queue_Adapter<ACE_Timer_Heap> ActiveTimer;
ActiveTimer就是你的定时器,你可以调用(比如)
ActiveTimer objActiveTimer;
objActiveTimer.schedule(this, NULL, ACE_Time_Value(MAX_MSG_STARTTIME), ACE_Time_Value(m_u2ThreadTimeCheck));

疑问?? 你传的模板参数是ACE_Timer_Heap    , ACE_Timer_Heap只提供的是schedule_i 接口,ACE_Thread_Timer_Queue_Adapter<TQ>::schedule函数实现里调用的是schedule(见下面注释部分),所以 这样用法 应该有问题的啊?


而template<class TQ> long
ACE_Thread_Timer_Queue_Adapter<TQ>::schedule
    (ACE_Event_Handler* handler,
   const void *act,
   const ACE_Time_Value &future_time,
   const ACE_Time_Value &interval)
{
ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, guard, this->mutex_, -1);

long const result = this->timer_queue_->schedule (handler, act, future_time, interval);          //这里调用的是schedule 接口啊
this->condition_.signal ();
return result;
}
页: [1]
查看完整版本: 有关Proactor的定时器的问题