[Ace-users] ACE_Reactor_Notification_Strategy flow control flaw

maxhell at mail.ru maxhell at mail.ru
Mon Aug 27 06:50:45 CDT 2007


Hi,

The ACE Programmer's Guide seems to be quite misleading in the way the
ACE_Reactor_Notification_Strategy is used with the ACE_Reactor and the
non-blocking sockets.
In the APG's examples ($ACE_ROOT/ACE_wrappers/examples/APG/Reactor)
the undelivered part of the message is put back on the message queue
when the socket becomes flow controlled during the message transfer in
the handle_output(). But using the ACE_Reactor_Notification_Strategy
ultimatly means that the handle_output() will be invoked again
immediately after (triggered by ungetq()). In the handle_output(), the
message is get from the queue and immediately put back (because the
socket is still flow controlled), triggering handle_output() over and
over again.
The Reactor hangs (consuming 100% CPU) until the message transfer is
complete.
This does not usually happen with 12 bytes long messages (as in
examples), but using this approach with larger messages/higher message
throughput/slower communication channels will lead into trouble.
To expose the effect I have increased the message size to 12700 bytes
$ACE_ROOT/ACE_wrappers/examples/APG/Reactor/Client.cpp:

34,36c34,37
<       ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%.*C"),
<                   static_cast<int> (recv_cnt),
<                   buf));
---
> // Less garbage in the output.
> //      ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%.*C"),
> //                  static_cast<int> (recv_cnt),
> //                  buf));
59c60
<   ACE_NEW_RETURN (mb, ACE_Message_Block (128), -1);
---
>   ACE_NEW_RETURN (mb, ACE_Message_Block (12800), -1);
61c62
<     (mb->wr_ptr (), "Iteration %d\n", this->iterations_);
---
>     (mb->wr_ptr (), "Iteration %012700d\n", this->iterations_);
71a73
>   ACE_DEBUG((LM_DEBUG, ACE_TEXT ("Client::handle_output\n")));
75a78,81
>       // The socket can become flow controlled if it is in the non-blocked mode.
>       // This is the default mode for ACE_WFMO_Reactor,
>         // for others it must be activated.
>       this->peer().enable(ACE_NONBLOCK);
104c110
<   ACE_INET_Addr port_to_connect (ACE_TEXT ("HAStatus"),
ACE_LOCALHOST);
---
>   ACE_INET_Addr port_to_connect (ACE_TEXT ("HAStatus"), ACE_TEXT ("test"));

The output (MS Windows 2000, 28800 bit/s line):

Client::handle_output
Client::handle_output
(3076|2376) send: Resource temporarily unavailable
Client::handle_output
(3076|2376) send: Resource temporarily unavailable
[the last two messages are repeated 307857 times]
Client::handle_output

As seen from the output, the Reactor is looped in
Client::handle_output() because of the increased message size and slow
communication channel.

Tested on ACE version 5.5, platform/compiler:
Solaris 9 (SPARC)/Sun C++ 5.5, HP-UX 11.0/gcc 3.2, Red Hat Enterprise
Linux 4.4 (i386)/gcc 3.4.6, MS Windows 2000/MS Visual Studio 6.6

Thanks,
Max Koltyapin



More information about the Ace-users mailing list