ACEのReactorモードの例のパラメータを修正してテストし、テスト結果に基づいて、Reactorが62のイベントの制限を突破できると推測します.でも...
6920 ワード
ACEのReactorモードの例のパラメータを修正してテストし、テスト結果に基づいて、Reactorが62のイベントの制限を突破できると推測します.しかし、事件が殺到すると、Reactorは対応が間に合わず、事件が漏れる現象が発生する.
ACE 6.0.0で提供される例Reactors_を次に示します.Testのソースコードの一部(ACE-6.0.0ACE_wrapperstestsディレクトリ).
Reactors_Test.cppファイルの一部の内容:
test_config.hファイル(ACE-6.0.0ACE_wrapperstestsディレクトリ)の一部の内容:
次の3つのパラメータテストを組み合わせて変更します.
1. MAX_TASKS
2.timeout(Test_Task::svc関数)
3. ACE_MAX_ITERATIONS
3つのパラメータの元の値:
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(例では2つのReactor)のイベント数は以下のように62を超えるように設定される.
static const int MAX_TASKS = 100;
これでtimeoutとACE_MAX_ITERATIONSの2つのパラメータ値の組み合わせが適切ではなく、ログファイルReactors_Test.log(ACE-6.0.0ACE_wrapperstestslogディレクトリの下)にイベント漏れのヒントが表示されます.以下のようになります.
LM_ERROR@(13432) notify: Resource temporarily unavailable
しかし、組み合わせが適切であれば、このようなヒントはありません.
また、トレースデバッグでは、Reactorが対応するイベントでACE_を呼び出していることが判明しました.WFMO_Reactor::poll_remaining_handles関数(ACE-6.0.0ACE_wrappersaceWFMO_Reactor.cppファイル):
関数の字面を見ると「残りのイベントハンドルに応答する」という意味です.
総じて推測できるかどうか:
Reactorは62個のイベントの制限を突破し、バッチ(最大62個まで)でイベントを監視することができるが、イベントが殺到すると、Reactorは対応が間に合わず、イベントが漏れる現象が発生する.
ACE 6.0.0で提供される例Reactors_を次に示します.Testのソースコードの一部(ACE-6.0.0ACE_wrapperstestsディレクトリ).
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
")));
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
"),
ACE_TEXT ("notify() timed out")));
else
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%t) %p
"),
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
"),
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
"),
ACE_TEXT ("reactor")),
0);
/* NOTREACHED */
case 0:
ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Reactor shutdown
")));
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
"),
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
"),
ACE_TEXT ("spawn")),
-1);
if (ACE_Thread_Manager::instance ()->wait () == -1)
ACE_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("%p
"),
ACE_TEXT ("wait")),
-1);
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("(%t) all threads are finished
")));
#else
ACE_ERROR ((LM_INFO,
ACE_TEXT ("threads not supported on this platform
")));
#endif /* ACE_HAS_THREADS */
ACE_END_TEST;
return 0;
}
test_config.hファイル(ACE-6.0.0ACE_wrapperstestsディレクトリ)の一部の内容:
#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 */
次の3つのパラメータテストを組み合わせて変更します.
1. MAX_TASKS
2.timeout(Test_Task::svc関数)
3. ACE_MAX_ITERATIONS
3つのパラメータの元の値:
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(例では2つのReactor)のイベント数は以下のように62を超えるように設定される.
static const int MAX_TASKS = 100;
これでtimeoutとACE_MAX_ITERATIONSの2つのパラメータ値の組み合わせが適切ではなく、ログファイルReactors_Test.log(ACE-6.0.0ACE_wrapperstestslogディレクトリの下)にイベント漏れのヒントが表示されます.以下のようになります.
LM_ERROR@(13432) notify: Resource temporarily unavailable
しかし、組み合わせが適切であれば、このようなヒントはありません.
また、トレースデバッグでは、Reactorが対応するイベントでACE_を呼び出していることが判明しました.WFMO_Reactor::poll_remaining_handles関数(ACE-6.0.0ACE_wrappersaceWFMO_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は対応が間に合わず、イベントが漏れる現象が発生する.