peakzhang 发表于 2008-9-10 22:55:55

Proactor使用中的问题

我在使用ACE5.5的时候,用到了其中的Proactor。
我的测试程序先创建了win32下的proactor后,在线程中启动了run_event_loop方法,然后在析构的时候调用了end_event_loop方法,可是每次在我调用end_event_loop方法的时候就要抛出一个异常,内容为:
"Unhandled exception in proact.exe(KERNEL32.DLL): 0xE06D7363: Microsoft C++ Exception"。
大家在使用ACE5.5的Proactor时有没有遇到过类似的问题呢?

下面是我的代码,只是简单的创建Proactor在删除它。
//异步反应器框架类

class SEA_Proactor : public ACE_Task<ACE_MT_SYNCH>
{
public :
SEA_Proactor():
      sem_ ((unsigned int) 0),
      proactor_(0){}
virtual ~SEA_Proactor()
{
      (void) this->stop ();//停止异步方应器
      this->delete_proactor();//删除已创建的异步反应器
}
    //启动异步反应器
virtual int start(int iThreads)//启动线程的数目)
{
//创建一个异步反应器
if(this->create_proactor() == -1)
   return -1;
      //启动异步方应器线程函数
      if(this->activate (THR_JOINABLE | THR_NEW_LWP,iThreads) == -1)
   return -1;
      //线程池中的每个线程等待获取线程锁
      for(;iThreads > 0;iThreads--)
{
            if(sem_.acquire() == -1)
    return -1;
}
      return 0;
}
    //停止异步方应器
virtual int stop(void)
{
//停止异步反应器内核运行
if(this->proactor_ != 0)
{
    ACE_Proactor::end_event_loop(); //执行到这一句就出错
}
//等待异步反应器线程函数结束
if(this->wait () == -1)
      return -1;
return 0;
}
    //异步方应器线程函数
virtual int svc(void)
{
//发出解锁信号表示线程函数已经开始运行
      sem_.release(1);
      //开始异步反应器内核运行
      ACE_Proactor::run_event_loop();
return 0;
}
private:
//创建一个异步反应器
    int create_proactor(void)
{
//定义一个32位windows操作系统下的异步反应器接口类的指针
      ACE_WIN32_Proactor *proactor_impl = 0;
      //实例化这个指针
      ACE_NEW_RETURN (proactor_impl,
                        ACE_WIN32_Proactor,
                        -1);
      //实例化一个ACE的异步反应器类,并和前一个异步反应器接口类绑定
      ACE_NEW_RETURN (this->proactor_,
                        ACE_Proactor (proactor_impl, 1 ),
                        -1);
      //将异步反应器单体类的实例指向实例化的ACE异步反应器类
      ACE_Proactor::instance (this->proactor_, 1);
      return 0;
}
    //删除已创建的异步反应器
    void delete_proactor(void)
{
if(this->proactor_ != 0)
{
      ACE_Proactor::close_singleton ();
            this->proactor_ = 0;
}
}
    ACE_Thread_Semaphore sem_;//线程池信号
ACE_Thread_Semaphore sem1_;//线程池信号
    ACE_Proactor * proactor_;//异步反应器实例指针
};
//main函数测试
int ACE_TMAIN(int argc, ACE_TCHAR *argv[])
{
SEA_Proactor *test;
ACE_NEW_RETURN(test, SEA_Proactor, -1);
test->start(1);
ACE_OS::sleep(1); //只要有这句话(换成scanf,或者弹出一个框,产生一个耽搁的时间)就要出错
delete test;   
return 0;
}

peakzhang 发表于 2008-9-10 22:56:08

代码里面错漏很多。
ACE_Task是不能直接删除的,需要让他停止队列的运作。
virtual int svc(void)
你的停止过程,是在析构函数里面,不推荐,因为析构函数里面运行,常常意味着其它附属资源的释放,比如你的类成员函数已经释放掉了。
(void) this->stop ();//停止异步方应器
this->delete_proactor();//删除已创建的异步反应器
这两句调用,缺乏同步关系,导致task被删除了,svc和Proactor还在跑,肯定报错。

peakzhang 发表于 2008-9-10 22:56:17

看了版主的回答,我还有以下几个问题:

1。"ACE_Task是不能直接删除的,需要让它停止队列的运作",我继承自ACE_Task是为了能让Proactor在线程里运行event_loop(),虽然ACE_Task里自带了一个msg_queue,但我并没有对它进行任何操作。斑竹的意思是让我加一句"this->msg_queue()->deactivate()"?

2。(void) this->stop ();//停止异步方应器
this->delete_proactor();//删除已创建的异步反应器
斑竹说上面这两句的调用缺乏同步关系,但我的问题是:每次调试只要到了end_event_loop()方法的时候就出错,我可以不把这些停止操作放在delete里面,可以在main函数里调用,但同样的,遇到end_event_loop时就要出错。我在end_event_loop调用之前需要做点什么其他的么?ACE提供给我们的就是一句end_event_loop。

peakzhang 发表于 2008-9-10 22:56:25

//定义一个32位windows操作系统下的异步反应器接口类的指针
      ACE_WIN32_Proactor *proactor_impl = 0;
      //实例化这个指针
      ACE_NEW_RETURN (proactor_impl,
                        ACE_WIN32_Proactor,
                        -1);
      //实例化一个ACE的异步反应器类,并和前一个异步反应器接口类绑定
      ACE_NEW_RETURN (this->proactor_,
                        ACE_Proactor (proactor_impl, 1 ),
                        -1);
      //将异步反应器单体类的实例指向实例化的ACE异步反应器类
      ACE_Proactor::instance (this->proactor_, 1);
---------------------------------------------------------

上面代码全部可以不要,改成:
this->proactor_ = ACE_Proactor::instance();
因为Windows平台,默认的初始化对象就是ACE_WIN32_Proactor.
故障消除,出错的地方在:
int
ACE_WIN32_Asynch_Result::post_completion (ACE_Proactor_Impl *proactor)
{
// Get to the platform specific implementation.
ACE_WIN32_Proactor *win32_proactor = dynamic_cast<ACE_WIN32_Proactor *> (proactor);

if (win32_proactor == 0)
    ACE_ERROR_RETURN ((LM_ERROR,
                     ACE_LIB_TEXT ("Dynamic cast to WIN32 Proactor failed\n")),
                      -1);

// Post myself.
return win32_proactor->post_completion (this);
}
你初始化的代码有问题,导致Proactor实际运行的,和你结束的不是一个对象,应该是这个问题。

ACE_Task的结束,需要等待svc结束,svc是另外的线程开启的,所以一般会wait()一下。
你的代码很危险,因为删除的对象和运行的线程之间没有同步关系,极其容易因为崩溃错误。
页: [1]
查看完整版本: Proactor使用中的问题