peakzhang 发表于 2008-7-15 22:25:35

Proactor 自带例子 问题

在ACE自带的例子中.D:\ACE_wrappers\examples\Reactor\Proactor
里面有个Proactor_End_Event_Loops. 运行是,结果正常,但是运行到
ACE_Thread_Manager::instance ()->wait (); 程序就停住了,并不能结束.
本人的运行环境: ACE - 5.5   ACE_AS_STATIC_LIBS操作系统WINXP
在LINUX 2.6.9-5.EL 下试过也是一样.
之前在用 Reactor时也遇到过 ACE_Thread_Manager::instance ()->wait (); 时出错,导致 core 掉.
请大家帮忙怎么解决.

// test_end_event_loop.cpp,v 1.7 2004/05/05 18:59:34 shuston Exp
// ============================================================================
//
// = FILENAME
//   test_end_event_loop.cpp
//
// = DESCRITPTION
//   This program tests the event loop mechanism of the
//   Proactor. To end the event loop, threads that are blocked in
//   waiting for completions arewoken up and the event loop comes
//   to the end. This is tested in this program.
//
//   Threads are doing <run_event_loop> with/without time_out
//   values and the main thread calls <end_event_loop>.
//
// = COMPILATION
//   make
//
// = RUN
//   ./test_end_event_loop
//
// = AUTHOR
//   Alexander Babu Arulanthu <alex@cs.wustl.edu>
//
// =====================================================================
#include "ace/OS_NS_unistd.h"
#include "ace/Proactor.h"
#include "ace/Task.h"
#include "ace/WIN32_Proactor.h"
#include "ace/POSIX_Proactor.h"
#include "ace/OS_main.h"
#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || \
   (defined (ACE_HAS_AIO_CALLS)) && !defined (ACE_POSIX_AIOCB_PROACTOR))
// This only works on Win32 platforms and on Unix platforms supporting
// POSIX aio calls.
class My_Task: public ACE_Task <ACE_NULL_SYNCH>
{
// = TITLE
//
//   Contains thread functions which execute event loops. Each
//   thread waits for a different signal.
//
public:
// Constructor.
My_Task (void)
    : time_flag_ (0)
    {}

virtual ~My_Task (void) {}
// Destructor.
// If time_flag is zero do the eventloop indefinitely, otherwise do
// it for finite amount of time (13secs!!!).
int open (void *timed_event_loop)
    {
      // Set the local variable.
      if (timed_event_loop == 0)
      this->time_flag_ = 0;
      else
      this->time_flag_ = 1;
      // Spawn the threads.
      if (this->activate (THR_NEW_LWP, 5) == -1)
      ACE_ERROR_RETURN ((LM_ERROR,
                           "%N:%l:%p\n",
                           "My_Task:open: <activate> failed"),
                        -1);
      return 0;
    }
// Thread function.
int svc (void)
    {
      ACE_DEBUG ((LM_DEBUG,
                  "(%P|%t):Starting svc routine\n"));
      if (this->time_flag_)
      {
          ACE_DEBUG ((LM_DEBUG,
                      "(%P|%t):Going to do *timed* <run_event_loop> \n"));
          ACE_Time_Value run_time (13);
          if (ACE_Proactor::instance ()->run_event_loop (run_time) == -1)
            ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t):%p.\n",
                               "<Proactor::run_event_loop> failed"),
                              -1);
      }
      else
      {
          ACE_DEBUG ((LM_DEBUG,
                      "(%P|%t):Going to do *indefinite* <run_event_loop> \n"));
          if (ACE_Proactor::instance ()->run_event_loop () == -1)
            ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t):%p.\n",
                               "<Proactor::run_event_loop> failed"),
                              -1);
      }
      return 0;
    };
private:
int time_flag_;
// If zero, indefinite event loop, otherwise timed event loop.
};
int
ACE_TMAIN (int argc, ACE_TCHAR *argv [])
{
ACE_UNUSED_ARG (argc);
ACE_UNUSED_ARG (argv);
ACE_DEBUG ((LM_DEBUG,
            "(%P | %t):Test starts \n"));
// Let us get the singleton proactor created here. This is very
// important. This will mask the signal used in the Proactor masked
// for the main thread (and all the threads).
ACE_Proactor *proactor = ACE_Proactor::instance ();
ACE_UNUSED_ARG (proactor);
My_Task task1, task2;
// Test the indefinite run event loop.
if (task1.open (0) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                     "%N:%l:(%P | %t):Failed to <open> the task\n"),
                      1);
// Test the indefinite run event loop. Just pass a non-zero.
if (task2.open ((void *)&task2) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                     "%N:%l:(%P | %t):Failed to <open> the task\n"),
                      1);
// Give a gap.
ACE_OS::sleep (3);
// End the event loop.
if (ACE_Proactor::instance ()->end_event_loop () == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                     "%N:%l:(%P | %t):Failed to <end_event_loop>\n"),
                      1);
ACE_Thread_Manager::instance ()->wait ();
ACE_DEBUG ((LM_DEBUG,
            "(%P | %t):Test ends\n"));
return 0;
}
#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class ACE_Task <ACE_NULL_SYNCH>;
#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
#pragma instantiate ACE_Task <ACE_NULL_SYNCH>
#endif /* ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA */
#else /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/
int
main (int, char *[])
{
ACE_DEBUG ((LM_DEBUG,
            "This example cannot work with AIOCB_Proactor.\n"));
return 1;
}
#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS && !ACE_POSIX_AIOCB_PROACTOR*/

peakzhang 发表于 2008-7-15 22:26:22

在ACE_Proactor里面,在默认,超时时是使用 ACE_Timer_Heap timer queue mechamism来分发事件,在
创建 ACE_Proactor时 创建了一个线程, 在proactor.cpp :349 行
// Set the timer queue.
this->timer_queue (tq);
// Create the timer handler
ACE_NEW (this->timer_handler_,
ACE_Proactor_Timer_Handler (*this));
// Activate <timer_handler>.
if (this->timer_handler_->activate (THR_NEW_LWP) == -1)
   
结合本例子,跟踪时,发现该线程 在proactor.cpp : 146行 等待了,
      else
    // The timer queue has no entries, so wait indefinitely.
    result = this->timer_event_.wait ();
而主线程ACE_Thread_Manager::instance ()->wait ();会不会因为这个而等待了,导致程序不能结束?


请大家帮帮忙,,急啊!!!

peakzhang 发表于 2008-7-15 22:26:34

这个是完全正常的程序行为,不是异常,不是程序的bug。所有人跑这个程序,都是这个结果。呵呵。

peakzhang 发表于 2008-7-15 22:26:43

如果要结束程序,需要使用一个Ctrl + C的响应中断。很简单的,ACE的例子里面有演示。

peakzhang 发表于 2008-7-15 22:26:50

谢谢 winston 的帮助.你的意思是

定义捕捉信号量类,handle_single 然后强行exit()程序 ?

使用了另外的方法也可以,不过实际可能不会这样用.

把所有创建的线程都归到一个组里面.

static int g_nGrpID = 10;

activate (THR_NEW_LWP|THR_JOINABLE , 3,0,ACE_DEFAULT_THREAD_PRIORITY,g_nGrpID)

在ACE_TMAIN 里面 使用:

ACE_Thread_Manager::instance ()->wait_grp(g_nGrpID);

这样就可以正常结束了.

正常结束程序很重要,析构类,最少不会有core文件.

peakzhang 发表于 2008-7-15 22:26:58

我说的不是强行结束,ACE的程序都是可以正常结束的。

peakzhang 发表于 2008-7-15 22:37:13

谢谢winston版主的关注,

你的意思是 发送一个 SIGINT /*中断*/信号什么的终断程序? 我试过直接 ctrl+c 关闭程序,发现自己定义的类是没有正常析构的.当然 ACE_Thread_Manager类里面是正常析够的.

有没有更好的解决办法?

我也试过加个信号处理类,但是捕捉到 SIGINT后,怎么样解除 ACE_Thread_Manager的wait();

virtual int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0)
{
ACE_TRACE (ACE_TEXT ("MySignalHandler::handle_signal"));

// Make sure the right handler was called back..
// ACE_ASSERT(signum == this->signum_);
ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("信号%d occured\n"), signum));

ACE_Reactor::instance()->end_reactor_event_loop();
//捕捉到CTRL + C 后这里需要如何处理???? 解除ACE_Thread_Manager的wait(),或者Proactor产生的线程 让程序正常结束?

return 0;
}

wishel 发表于 2008-8-3 19:27:35

可以不用ACE_Thread_Manager::instance ()->wait ();


task1.wait();
task2.wait();
代替

wishel 发表于 2008-8-3 20:50:42

发现proactor和ACE_Thread_Manager::instance ()->wait ()有冲突

int
ACE_TMAIN (int argc, ACE_TCHAR *argv [])
{
ACE_DEBUG ((LM_DEBUG,
            "(%P | %t):Test begins\n"));
ACE_Proactor::instance ();
ACE_Thread_Manager::instance ()->wait ();
ACE_DEBUG ((LM_DEBUG,
            "(%P | %t):bye!\n"));
return 0;
}
就不会走到结束,如果把ACE_Proactor::instance ();这一行注释掉就可以。
按道理不应该这样,应该算是bug了吧。

winston 发表于 2008-8-3 21:33:08

没有冲突。我所有的系统中,都是用ACE_Thread_Manager::instance ()的。你用法不对头。
页: [1] 2
查看完整版本: Proactor 自带例子 问题