修改ACE的Reactor模式示例中的参数后测试,依据测试结果,猜测Reactor似乎可以突破62个事件的限制。但当事件蜂拥而上时,Reactor会由于应对不及,而出现事件漏掉的现象。
下面是在 ACE 6.0.0 提供的示例 Reactors_Test 的部分源代码 (在 \ACE-6.0.0\ACE_wrappers\tests\ 目录下)。
Reactors_Test.cpp 文件部分内容:
#if defined (ACE_HAS_THREADS)
ACE_Thread_Manager *thr_mgr;
static const int MAX_TASKS = 20;
...
int
Test_Task::svc (void)
{
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("(%t) svc\n")));
for (size_t i = 0; i < ACE_MAX_ITERATIONS; i++)
{
ACE_OS::thr_yield ();
// Only wait up to 10 milliseconds to notify the Reactor.
ACE_Time_Value timeout (0, 10 * 1000);
if (this->reactor ()->notify (this,
ACE_Event_Handler::READ_MASK,
&timeout) == -1)
{
if (errno == ETIME)
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("(%t) %p\n"),
ACE_TEXT ("notify() timed out")));
else
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%t) %p\n"),
ACE_TEXT ("notify")),
-1);
}
}
return 0;
}
int
Test_Task::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
{
return 0;
}
int
Test_Task::handle_input (ACE_HANDLE)
{
this->handled_++;
if (this->handled_ == ACE_MAX_ITERATIONS)
{
done_count--;
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("(%t) handle_input, handled_ = %d, done_count = %d\n"),
this->handled_,
done_count.value ()));
}
ACE_OS::thr_yield ();
return -1;
}
static void *
worker (void *args)
{
ACE_Reactor *reactor = reinterpret_cast<ACE_Reactor *> (args);
// Make this thread the owner of the Reactor's event loop.
reactor->owner (ACE_Thread::self ());
// Use a timeout to inform the Reactor when to shutdown.
ACE_Time_Value timeout (4);
for (;;)
switch (reactor->handle_events(timeout))
{
case -1:
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%t) %p\n"),
ACE_TEXT ("reactor")),
0);
/* NOTREACHED */
case 0:
ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Reactor shutdown\n")));
return 0;
}
ACE_NOTREACHED (return 0);
}
#endif /* ACE_HAS_THREADS */
int
run_main (int, ACE_TCHAR *[])
{
ACE_START_TEST (ACE_TEXT ("Reactors_Test"));
#if defined (ACE_HAS_THREADS)
ACE_ASSERT (ACE_LOG_MSG->op_status () != -1);
thr_mgr = ACE_Thread_Manager::instance ();
ACE_Reactor reactor;
ACE_ASSERT (ACE_LOG_MSG->op_status () != -1);
Test_Task tt1[MAX_TASKS];
Test_Task tt2[MAX_TASKS];
// Activate all of the Tasks.
for (int i = 0; i < MAX_TASKS; i++)
{
tt1[i].open (ACE_Reactor::instance ());
tt2[i].open (&reactor);
}
// Spawn two threads each running a different reactor.
if (ACE_Thread_Manager::instance ()->spawn
(ACE_THR_FUNC (worker),
(void *) ACE_Reactor::instance (),
THR_BOUND | THR_DETACHED) == -1)
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("spawn")),
-1);
else if (ACE_Thread_Manager::instance ()->spawn
(ACE_THR_FUNC (worker), (void *) &reactor,
THR_BOUND | THR_DETACHED) == -1)
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("spawn")),
-1);
if (ACE_Thread_Manager::instance ()->wait () == -1)
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("wait")),
-1);
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("(%t) all threads are finished\n")));
#else
ACE_ERROR ((LM_INFO,
ACE_TEXT ("threads not supported on this platform\n")));
#endif /* ACE_HAS_THREADS */
ACE_END_TEST;
return 0;
}
test_config.h文件(在 \ACE-6.0.0\ACE_wrappers\tests\ 目录下)部分内容:
#ifndef ACE_TEST_CONFIG_H
#define ACE_TEST_CONFIG_H
...
size_t const ACE_NS_MAX_ENTRIES = 1000;
size_t const ACE_DEFAULT_USECS = 1000;
size_t const ACE_MAX_TIMERS = 4;
size_t const ACE_MAX_DELAY = 10;
size_t const ACE_MAX_INTERVAL = 0;
size_t const ACE_MAX_ITERATIONS = 10;
size_t const ACE_MAX_PROCESSES = 10;
size_t const ACE_MAX_THREADS = 4;
...
#endif /* ACE_TEST_CONFIG_H */
搭配修改下面三个参数测试:
1. MAX_TASKS
2. timeout (在Test_Task::svc 函数里)
3. ACE_MAX_ITERATIONS
三个参数的原值:
static const int MAX_TASKS = 20;
ACE_Time_Value timeout (0, 10 * 1000);
size_t const ACE_MAX_ITERATIONS = 10;
如果把 MAX_TASKS值设成大于62(比如 100),即把每个Reactor(示例中有两个Reactor)的事件数设置超过62个,如下:
static const int MAX_TASKS = 100;
这样,如果 timeout 和 ACE_MAX_ITERATIONS 两个参数值搭配设置不当,在日志文件Reactors_Test.log(在\ACE-6.0.0\ACE_wrappers\tests\log目录下)中就会出现有事件漏掉的提示,如下:
LM_ERROR@(13432) notify: Resource temporarily unavailable
但如果搭配设置恰当,就没有这样的提示。
另外,跟踪调试发现,Reactor在相应事件时调用了ACE_WFMO_Reactor::poll_remaining_handles 函数(在\ACE-6.0.0\ACE_wrappers\ace\WFMO_Reactor.cpp文件中):
DWORD
ACE_WFMO_Reactor::poll_remaining_handles (DWORD slot)
{
return ::WaitForMultipleObjects (this->handler_rep_.max_handlep1 () - slot,
this->handler_rep_.handles () + slot,
FALSE,
0);
}
看函数字面意思是“响应余下的事件句柄”之意。
综上是否可猜测:
Reactor可以突破62个事件的限制,分批(最多62个一批)监视事件,但当事件蜂拥而上时,Reactor会由于应对不及,而出现事件漏掉的现象。