tempus 发表于 2012-8-6 13:40:54

关于ACE_Reactor的Accetpor-Connector框架的应用问题?急!!!

本帖最后由 tempus 于 2012-8-7 09:16 编辑

我目前是在linux下用ACE开发一个关于TCP的通道模块,运用了ACE_Reactor的Accetpor-Connector框架,其中实现了一个服务处理器,ChannelSvcHandler:public ACE_SVC_Handler<>,并在其open函数activate,激活了一个主动线程,用于从队列中取数据并发送给对端,若取出的是MB_STOP类型的消息则退出。
对于连接的反应式关闭我是这样设计的,当网络异常或对端关闭时,handle_input肯定会接收到反应器通知,在handle_input中,当recv返回值为0时,我向队列中插入类型为MB_STOP的消息,然后wait等待SVC线程退出,之后直接返回0。因为我想主动线程退出时,会调用handle_close来进行清理工作。
现在出现的问题是,我在调用wait时,一直不能返回,导致我的handle_input不能正常结束,阻塞在那里,我确定我的svc线程肯定是返回了,因为svc返回前的打印输出成功了。后来我又试了将activate的参数加入THR_DETACHED,然后不调用wait直接返回,但问题又出现了,在对端关闭时,handle_input函数被调用了多次,最少3次,最多7,8次,这我实在搞不懂。
现在我的问题是,首先,对于我这种带主动线程的服务处理器,反应式关闭时,利用退出线程来关闭连接不知道合不合适,因为我觉得线程肯定是要退出的,既然线程退出会调用handle_close,何不就这样退出了,就不需要在handle_input里面返回-1了吧?如果合适,那上面出现的两个问题是什么原因呢,会不会跟linux里面反应器的默认实现是select_reactor有关?如果不合适,那我到底该怎样处理反应式关闭呢??
这个问题比较急,希望有高人指点,感激不尽!!!

代码倒没啥隐私的,现将我到代码贴下,我也是个初学者,可能有写到不合适的地方,望大家指点。。。谢谢

class ChannelSvcHandler : public ACE_Svc_Handler<ACE_SOCK_STREAM,ACE_MT_SYNCH> {
    typedef ACE_Svc_Handler<ACE_SOCK_STREAM,ACE_MT_SYNCH> PARENT;

public:
    ChannelSvcHandler();
    virtual ~ChannelSvcHandler();

public:
    //打开服务处理器
    virtual int open (void *p);
    //接收处理函数
    virtual int handle_input (ACE_HANDLE fd);
    //数据发送线程
    virtual int svc();
    //退出线程并关闭连接
    int QuitSvcAndClose(bool bupdate = true);

private:
    //通道连接器指针
    ChannelConnector * pConnector_;
};

int ChannelSvcHandler::open(void *p) {
    //调用父类函数,完成向反应器注册
    PARENT::open();

    //保存通道连接器指针
    if (0 != p) {
      pConnector_ = reinterpret_cast<ChannelConnector *>(p);
    }

    //激活数据发送线程
    this->activate();
    return 0;
}

int ChannelSvcHandler::handle_input(ACE_HANDLE fd) {
    //创建接收缓存
    ACE_Message_Block *mbk = 0;
    ACE_NEW_RETURN(mbk,ACE_Message_Block(DEFAULT_BLOCK_SIZE),0);

    //接收数据
    ssize_t count = this->peer().recv(mbk->wr_ptr(),mbk->size());

    if (count > 0) {
      //接收成功,移动写指针
      mbk->wr_ptr(count);
      //返回接收数据
      if (!pConnector_->PutReceiveMessage(mbk)) {
            mbk->release();
            ACE_ERROR((LM_ERROR,ACE_TEXT("接收数据返回失败!\n")));
      }
    } else {
      //接收失败,表示对端关闭或网络异常
      mbk->release();
      ACE_DEBUG((LM_DEBUG,ACE_TEXT("连接异常,将断开与对端到连接!\n")));
      //退出线程并关闭连接
      QuitSvcAndClose();
    }

    return 0;
}

int ChannelSvcHandler::svc() {
    ACE_Message_Block *mbk;

    while (1) {
      //从队列获取数据
      if (-1 != this->getq(mbk)) {
            //判断是否为退出消息
            if (mbk->size() == 0 && mbk->msg_type() == ACE_Message_Block::MB_STOP) {
                //是则跳出循环,退出线程,关闭连接
                mbk->release();
                msg_queue()->close();
                ACE_DEBUG((LM_DEBUG,ACE_TEXT("收到退出消息,数据发送线程退出,并断开连接!\n")));
                break;
            } else {
                //否则为需发送到数据
                while (mbk->length() > 0) {
                  //发送数据到对端
                  ssize_t count = this->peer().send(mbk->rd_ptr(),mbk->length());
                  if (count > 0) {
                        //发送成功,移动读指针
                        mbk->rd_ptr(count);
                  } else {
                        //发送失败,表示网络异常,直接跳出,等待接收处理函数处理
                        break;
                  }
                }
                //发送完毕后释放资源
                mbk->release();
            }
      }
    }

    return 0;
}

int ChannelSvcHandler::QuitSvcAndClose(bool bupdate) {
    //判断是否需要更新通道连接器中到服务处理器指针
    if (bupdate) {
      pConnector_->UpdateSvcHandler();
    }

    //构造退出消息
    ACE_Message_Block *quit_msg = 0;
    ACE_NEW_RETURN(quit_msg,ACE_Message_Block(0,ACE_Message_Block::MB_STOP),0);

    //放入队列头
    if (-1 == this->ungetq(quit_msg)) {
      ACE_ERROR_RETURN((LM_ERROR,ACE_TEXT("退出消息压入队列失败!\n")),0);
    }

    //等待数据发送线程退出
    this->wait();

    return 1;
}

我再将问题具体说说,如果因为某种原因或主动关闭程序,从程序主线程中调用QuitSvcAndClose,该服务处理器可正常关闭;如果所对端关闭或网络异常等原因,导致handle_input中接收到的数据为0,这时我也会调用QuitSvcAndClose来先关闭线程,进而关闭服务处理器,但这时候QuitSvcAndClose中到this->wait就一直不返回阻塞在那,svc线程中的ACE_DEBUG((LM_DEBUG,ACE_TEXT("收到退出消息,数据发送线程退出,并断开连接!\n")))这条日志已经打印,表示线程已退出,为什么会不返回呢,不知道我在handle_input中调用这样到这样到退出线程到函数再等待线程退出是否合适????
后来我想直接把open函数中的activate参数设成THR_DETACHED,然后QuitSvcAndClose中不掉用wait直接返回,程序没有阻塞正常运行了,但通过打印到信息可以看出,hande_input函数貌似被调用了N次,这是我最搞不懂到地方!!!至于开启到线程到底是该设成THR_DETACHED还算THR_JOINABLE,两者到区别除了一个所系统自动回收资源,另一个是需要wait才能回收外,还有啥区别,我们该如何选择呢???

winston 发表于 2012-8-6 14:48:29

如果不涉及私密问题,请上传一点代码,大家帮你分析原因。

steven99ca 发表于 2012-8-24 00:55:49

比较乱,比如重要的handleinput实现,不仅效率低而且后患无穷。改改设计,这类问题基本上可以通过一个数据收发对象和一个或几个数据处理对象来解决,他们可以是eventhandler对象,耦合度很好,你还可以仍然使用msgqueue来同步数据。
页: [1]
查看完整版本: 关于ACE_Reactor的Accetpor-Connector框架的应用问题?急!!!