关于自动回调的问题,请指教~~~
昨天问的问题还是有相关的没有太弄明白,请多指点指点~~~class ServerHander :public ACE_Service_Handler
{
......
if (this->m_writer.write( *mb,mb_length ) != 0)
{
cout<<"Server write failed..."<<endl;
mb->release();
return -1;
}
else
{
if( this->m_reader.read( *mba,mba_length ) != 0 )
{
mba->release();
return -1;
}
}
}
如果我在某一段中调用了写操作,按理说应该回调 handle_write_stream,可是成功后 我又开始读操作了,读完后自动回调handle_read_stream,如果已经回调了 handle_read_stream ,而handle_write_stream还没有被回调,而此时,发现已经应该关闭该连接了,那么我就在handle_read_stream 里关闭连接,可是我想问的是,如果我在handle_read_stream 里要等待handle_write_stream 回调完才该关闭,那么 handle_read_stream 和 handle_write_stream 是不是在同一个线程里执行呢,如果是,那我怎么在 handle_read_stream 里等都不可能完成的呀? 如果不能完成,那么我应该在哪里等待 handle_write_stream 完成呢?
请高人们指教一下~~~~ 谢谢~~~~~~ 这是ACE的精妙和难解之处 1、handle_read_stream 和 handle_write_stream 是不是在同一个线程里执行呢
不一定,看你的设计了。一般不是一个线程,取决于并发设计。
2、不需要等待它完成,handle_write_stream 会自己处理。
我简单解释一下里面的事情:恰好是刚刚有人问过我,我顺便整理一下,贴出来。
关闭时候系统只有两种情况发生
1、你自己主动关闭
2、对方关闭,被你探查到了。
第一种情况,你会在操作完成后,调用closesocket。就是这段
ACE_OS::closesocket(this->handle());
this->handle(ACE_INVALID_HANDLE);
ACE后面的机制是:
while(TRUE)
{
// Wait for I/O to complete on any socket
// associated with the completion port
ret = GetQueuedCompletionStatus(CompletionPort,
XXXXXXXXXXXXXX//循环取结果
就一定会调用handle_read_stream和handle_write_stream,执行必要的清理操作。
第二种情况
你探查到了对方关闭,则你在handle_read_stream中会返回出错,你会间接调用closesocket,而这会引起handle_write_stream被调用
this->application_specific_code (asynch_result,
static_cast<size_t> (bytes_transferred),
(void *)
这是handle_events里面的代码,application_specific_code会调用handle_read_stream和handle_write_stream的
在检测到对方关闭后,handle_read_stream会被调用,但后面又调用了closesocket,会不会返回2次
答案是不会。因为你只投递了一个异步读取请求,也就响应一次,不会再次触发。所以只会再次调用handle_write_stream一次,清理系统。 如老大的解释,昨天一直困扰我的是closesocket之后,
为什么GetQueuedCompletionStatus会被调用了两次,
也就是handle_read_stream和handle_write_stream为什么一定会被调用到。
原因很简单,前面分别投递了异步的读写,m_writer.write,m_reader.read。
然后内部ACE_WIN32_Asynch_Read_Stream_Result与ACE_WIN32_Asynch_Write_Stream_Result则分别会被创建,
并通过真正的windows的异步读写接口(::ReadFile,::WriteFile)被iocp记录。之后一切正常运作。
然后如果主动或者被动的调用closesocket,Iocp检测到Handle被置成无效句柄了,自然不会坐视不理,
因为前面注册进去的这两个Result对应的句柄已经失效了。我估计系统至少会遍历这个无效的句柄对应的Result,恰好有两个,
因此就PostQueuedCompletionStatus两次,把这两个Result返还给我们自己,
当然如果没有投递任何异步的操作,PostQueuedCompletionStatus可能就不会被调用。
这样我们通过GetQueuedCompletionStatus就会拿到两次Result,因为这是我们预先注册进去的。
对Result进行简单的类型转换之后,即可以轻松的调用到对应的handle_xxx系列函数。
上面说的,都是ACE给我们封装好的,我们在自己实现的Handle_xxx里最后的内存清理工作,以及的delete this,
因此不会有任何的内存泄露,但是切记要保证最后只有一个入口可以调用到delete this,否则必定会崩溃。
所谓是失之毫厘,谬以千里,这次用在我的身上是最恰当不过了。
对概念的理解看似差了一点点,其实实际上确少走了很多步,少考虑了很多问题。
[ 本帖最后由 modern 于 2009-4-2 10:18 编辑 ] 受教了,领悟中,谢谢高人们的指点~~~
页:
[1]