在Windows系统下,ACE中的 Reactor 最终调用 WaitForMultipleObjects 函数,Priority Reactor 和 Proactor 最终调用 select 函数。

在Windows系统下,调试跟踪 ACE 6.0.0 提供的示例程序,发现 Reactor 最终调用系统的 WaitForMultipleObjects 函数,Priority Reactor 和 Proactor 最终调用系统的 select 函数。

三个示例程序源代码都在 \ACE-6.0.0\ACE_wrappers\tests\ 目录下。

Reactor 的 Reactors_Test.cpp 文件部分内容:

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;
}

Priority Reactor 的 Priority_Reactor_Test.cpp 部分内容:

int
run_main (int argc, ACE_TCHAR *argv[])
{
  ACE_START_TEST (ACE_TEXT ("Priority_Reactor_Test"));

  //FUZZ: disable check_for_lack_ACE_OS
  ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("dc:l:m:t:"));

  for (int c; (c = getopt ()) != -1; )
    switch (c)
      {
  //FUZZ: enable check_for_lack_ACE_OS
      case 'd':
        opt_priority_reactor = 0;
        break;
      case 'c':
        opt_nchildren = ACE_OS::atoi (getopt.opt_arg ());
        break;
      case 'l':
        opt_nloops = ACE_OS::atoi (getopt.opt_arg ());
        break;
      case 'm':
        max_retries = ACE_OS::atoi (getopt.opt_arg ());
        break;
      case 't':
        opt_max_duration = ACE_OS::atoi (getopt.opt_arg ());
        break;
      case '?':
      default:
        ACE_ERROR_RETURN ((LM_ERROR,
                           ACE_TEXT ("Usage: Priority_Reactor_Test ")
                           ACE_TEXT ("   [-d] (disable priority reactor)\n")
                           ACE_TEXT ("   [-c nchildren] (number of threads/processes)\n")
                           ACE_TEXT ("   [-l loops] (number of loops per child)\n")
                           ACE_TEXT ("   [-m maxretries] (attempts to connect)\n")
                           ACE_TEXT ("   [-t max_time] (limits test duration)\n")),
                          -1);
        ACE_NOTREACHED (break);
      }

  // Manage Reactor memory automagically.
  // Note:  If opt_priority_reactor is false, the default ACE_Reactor is used
  // and we don't need to set one up.
  ACE_Reactor *orig_reactor = 0;
  auto_ptr<ACE_Reactor> reactor;

  if (opt_priority_reactor)
    {
      ACE_Select_Reactor *impl_ptr;
      ACE_NEW_RETURN (impl_ptr, ACE_Priority_Reactor, -1);
      auto_ptr<ACE_Select_Reactor> auto_impl (impl_ptr);

      ACE_Reactor *reactor_ptr;
      ACE_NEW_RETURN (reactor_ptr, ACE_Reactor (impl_ptr, 1), -1);
      auto_impl.release ();   // ACE_Reactor dtor will take it from here
      auto_ptr<ACE_Reactor> auto_reactor (reactor_ptr);
      reactor = auto_reactor;
      orig_reactor = ACE_Reactor::instance (reactor_ptr);
    }

  Read_Handler::set_countdown (opt_nchildren);

  // Acceptor
  ACCEPTOR acceptor;

  acceptor.priority (ACE_Event_Handler::HI_PRIORITY);
  ACE_INET_Addr server_addr;

  // Bind acceptor to any port and then find out what the port was.
  if (acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)) == -1
      || acceptor.acceptor ().get_local_addr (server_addr) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       ACE_TEXT ("(%P|%t) %p\n"),
                       ACE_TEXT ("open")),
                      -1);

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("(%P|%t) starting server at port %d\n"),
              server_addr.get_port_number ()));

  ACE_INET_Addr connection_addr (server_addr.get_port_number (),
                                 ACE_DEFAULT_SERVER_HOST);

  int i;

#if defined (ACE_HAS_THREADS)
  for (i = 0; i < opt_nchildren; ++i)
    {
      if (ACE_Thread_Manager::instance ()->spawn
          (ACE_THR_FUNC (client),
           (void *) &connection_addr,
           THR_NEW_LWP | THR_DETACHED) == -1)
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("(%P|%t) %p\n%a"),
                    ACE_TEXT ("thread create failed"),
                    1));
    }
#elif !defined (ACE_LACKS_FORK)
  for (i = 0; i < opt_nchildren; ++i)
    {
      switch (ACE_OS::fork ("child"))
        {
        case -1:
          ACE_ERROR ((LM_ERROR,
                      ACE_TEXT ("(%P|%t) %p\n%a"),
                      ACE_TEXT ("fork failed"),
                      1));
          ACE_OS::exit (-1);
          /* NOTREACHED */
        case 0:
          client (&connection_addr);
          ACE_OS::exit (0);
          break;
          /* NOTREACHED */
        default:
          break;
          /* NOTREACHED */
        }
    }
#else
  ACE_ERROR ((LM_INFO,
              ACE_TEXT ("(%P|%t) ")
              ACE_TEXT ("only one thread may be run ")
              ACE_TEXT ("in a process on this platform\n")));
#endif /* ACE_HAS_THREADS */

  ACE_Time_Value tv (opt_max_duration);

  ACE_Reactor::instance()->register_handler
    (&acceptor, ACE_Event_Handler::READ_MASK);
  ACE_Reactor::instance()->run_reactor_event_loop (tv);

  if (Read_Handler::get_countdown () != 0)
    {
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("(%P|%t) running out of time, ")
                  ACE_TEXT ("probably due to failed connections.\n")));
    }

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("(%P|%t) waiting for the children...\n")));

#if defined (ACE_HAS_THREADS)
  ACE_Thread_Manager::instance ()->wait ();
#elif !defined (ACE_WIN32) && !defined (VXWORKS)
  for (i = 0; i < opt_nchildren; ++i)
    {
      pid_t pid = ACE_OS::wait();
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("(%P|%t) child %d terminated\n"),
                  pid));
    }
#else
  /* NOTREACHED */
  // We aborted on the previous #ifdef
#endif /* ACE_HAS_THREADS */

  if (orig_reactor != 0)
    ACE_Reactor::instance (orig_reactor);

  ACE_END_TEST;
  return 0;
}

Proactor  的 Proactor_Test.cpp 文件部分内容:

int
run_main (int argc, ACE_TCHAR *argv[])
{
  ACE_START_TEST (ACE_TEXT ("Proactor_Test"));

  if (::parse_args (argc, argv) == -1)
    return -1;

  disable_signal (ACE_SIGRTMIN, ACE_SIGRTMAX);
  disable_signal (SIGPIPE, SIGPIPE);

  MyTask    task1;
  TestData  test;

  if (task1.start (threads, proactor_type, max_aio_operations) == 0)
    {
      Acceptor  acceptor (&test);
      Connector connector (&test);
      ACE_INET_Addr addr (port);

      int rc = 0;

      if (both != 0 || host == 0) // Acceptor
        {
          // Simplify, initial read with zero size
          if (acceptor.open (addr, 0, 1) == 0)
            rc = 1;
        }

      if (both != 0 || host != 0)
        {
          if (host == 0)
            host = ACE_LOCALHOST;

          if (addr.set (port, host, 1, addr.get_type ()) == -1)
            ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), host));
          else
            rc += connector.start (addr, clients);
        }

      // Wait a few seconds to let things get going, then poll til
      // all sessions are done. Note that when we exit this scope, the
      // Acceptor and Connector will be destroyed, which should prevent
      // further connections and also test how well destroyed handlers
      // are handled.
	  ACE_OS::sleep (3);
    }
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Sleeping til sessions run down.\n")));
  while (!test.testing_done ())
    ACE_OS::sleep (1);

  test.stop_all ();

  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Stop Thread Pool Task\n")));
  task1.stop ();

  ACE_END_TEST;

  return 0;
}


Reactor 调用 \ACE-6.0.0\ACE_wrappers\ace\WFMO_Reactor.cpp 文件里的 ACE_WFMO_Reactor::poll_remaining_handles 函数,函数里调用了系统的 WaitForMultipleObjects 函数。下面是 ACE_WFMO_Reactor::poll_remaining_handles 函数:

DWORD
ACE_WFMO_Reactor::poll_remaining_handles (DWORD slot)
{
  return ::WaitForMultipleObjects (this->handler_rep_.max_handlep1 () - slot,
                                   this->handler_rep_.handles () + slot,
                                   FALSE,
                                   0);
}


Priority Reactor 和 Proactor 调用 \ACE-6.0.0\ACE_wrappers\ace\Select_Reactor_T.cpp 文件里的 ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::wait_for_multiple_events 函数,其中调用了 ACE_OS::select 函数,而其中调用了系统的 select 函数。

ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::wait_for_multiple_events 函数:

// Must be called with lock held.

template <class ACE_SELECT_REACTOR_TOKEN> int
ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::wait_for_multiple_events
  (ACE_Select_Reactor_Handle_Set &dispatch_set,
   ACE_Time_Value *max_wait_time)
{
  ACE_TRACE ("ACE_Select_Reactor_T::wait_for_multiple_events");
  ACE_Time_Value timer_buf (0);
  ACE_Time_Value *this_timeout = 0;

  int number_of_active_handles = this->any_ready (dispatch_set);

  // If there are any bits enabled in the <ready_set_> then we'll
  // handle those first, otherwise we'll block in <select>.

  if (number_of_active_handles == 0)
    {
      do
        {
          if (this->timer_queue_ == 0)
            return 0;

          this_timeout =
            this->timer_queue_->calculate_timeout (max_wait_time,
                                                   &timer_buf);
#ifdef ACE_WIN32
          // This arg is ignored on Windows and causes pointer
          // truncation warnings on 64-bit compiles.
          int const width = 0;
#else
          int const width = this->handler_rep_.max_handlep1 ();
#endif  /* ACE_WIN32 */

          dispatch_set.rd_mask_ = this->wait_set_.rd_mask_;
          dispatch_set.wr_mask_ = this->wait_set_.wr_mask_;
          dispatch_set.ex_mask_ = this->wait_set_.ex_mask_;

          number_of_active_handles = ACE_OS::select (width,
                                                     dispatch_set.rd_mask_,
                                                     dispatch_set.wr_mask_,
                                                     dispatch_set.ex_mask_,
                                                     this_timeout);
        }
      while (number_of_active_handles == -1 && this->handle_error () > 0);

      if (number_of_active_handles > 0)
        {
#if !defined (ACE_WIN32)
          // Resynchronize the fd_sets so their "max" is set properly.
          dispatch_set.rd_mask_.sync (this->handler_rep_.max_handlep1 ());
          dispatch_set.wr_mask_.sync (this->handler_rep_.max_handlep1 ());
          dispatch_set.ex_mask_.sync (this->handler_rep_.max_handlep1 ());
#endif /* ACE_WIN32 */
        }
      else if (number_of_active_handles == -1)
        {
          // Normally, select() will reset the bits in dispatch_set
          // so that only those filed descriptors that are ready will
          // have bits set.  However, when an error occurs, the bit
          // set remains as it was when the select call was first made.
          // Thus, we now have a dispatch_set that has every file
          // descriptor that was originally waited for, which is not
          // correct.  We must clear all the bit sets because we
          // have no idea if any of the file descriptors is ready.
          //
          // NOTE: We dont have a test case to reproduce this
          // problem. But pleae dont ignore this and remove it off.
          dispatch_set.rd_mask_.reset ();
          dispatch_set.wr_mask_.reset ();
          dispatch_set.ex_mask_.reset ();
        }
    }

  // Return the number of events to dispatch.
  return number_of_active_handles;
}

 

ACE_OS::select 函数:

// It would be really cool to add another version of select that would
// function like the one we're defending against below!
ACE_INLINE int
ACE_OS::select (int width,
                fd_set *rfds, fd_set *wfds, fd_set *efds,
                const ACE_Time_Value *timeout)
{
  ACE_OS_TRACE ("ACE_OS::select");
#if defined (ACE_HAS_NONCONST_SELECT_TIMEVAL)
  // We must defend against non-conformity!
  timeval copy;
  timeval *timep = 0;

  if (timeout != 0)
    {
      copy = *timeout;
      timep = &copy;
    }
  else
    timep = 0;
#else
  const timeval *timep = (timeout == 0 ? (const timeval *)0 : *timeout);
#endif /* ACE_HAS_NONCONST_SELECT_TIMEVAL */
#if defined (ACE_LACKS_SELECT)
  ACE_UNUSED_ARG (width);
  ACE_UNUSED_ARG (rfds);
  ACE_UNUSED_ARG (wfds);
  ACE_UNUSED_ARG (efds);
  ACE_UNUSED_ARG (timeout);
  ACE_NOTSUP_RETURN (-1);
#elif defined(ACE_TANDEM_T1248_PTHREADS)
  ACE_SOCKCALL_RETURN (::spt_select (width, rfds, wfds, efds, timep),
                       int, -1);
#else
  ACE_SOCKCALL_RETURN (::select (width, rfds, wfds, efds, timep),
                       int, -1);
#endif
}



 

 

 

你可能感兴趣的:(在Windows系统下,ACE中的 Reactor 最终调用 WaitForMultipleObjects 函数,Priority Reactor 和 Proactor 最终调用 select 函数。)