ACEのReactorモードの例のパラメータを修正してテストし、テスト結果に基づいて、Reactorが62のイベントの制限を突破できると推測します.でも...

6920 ワード

ACEのReactorモードの例のパラメータを修正してテストし、テスト結果に基づいて、Reactorが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は対応が間に合わず、イベントが漏れる現象が発生する.