PingPong.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2002-2008 Andreas Huber Doenni
  3. // Distributed under the Boost Software License, Version 1.0. (See accompany-
  4. // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. //////////////////////////////////////////////////////////////////////////////
  6. //////////////////////////////////////////////////////////////////////////////
  7. // #define USE_TWO_THREADS // ignored for single-threaded builds
  8. // #define CUSTOMIZE_MEMORY_MANAGEMENT
  9. //////////////////////////////////////////////////////////////////////////////
  10. // The following example program demonstrates the use of asynchronous state
  11. // machines. First, it creates two objects of the same simple state machine
  12. // mimicking a table tennis player. It then sends an event (the ball) to the
  13. // first state machine. Upon reception, the first machine sends a similar
  14. // event to the second state machine, which then sends the event back to the
  15. // first machine. The two machines continue to bounce the event back and forth
  16. // until one machine "has enough" and aborts the game. The two players don't
  17. // "know" each other, they can only pass the ball back and forth because the
  18. // event representing the ball also carries two boost::function objects.
  19. // Both reference the fifo_scheduler<>::queue_event() function, binding the
  20. // scheduler and the handle of the opponent. One can be used to return the
  21. // ball to the opponent and the other can be used to abort the game.
  22. // Depending on whether the program is compiled single-threaded or
  23. // multi-threaded and the USE_TWO_THREADS define above, the two
  24. // machines either run in the same thread without/with mutex locking or in two
  25. // different threads with mutex locking.
  26. //////////////////////////////////////////////////////////////////////////////
  27. #include "Player.hpp"
  28. #include <boost/statechart/asynchronous_state_machine.hpp>
  29. #include <boost/statechart/fifo_worker.hpp>
  30. #include <boost/mpl/list.hpp>
  31. #include <boost/config.hpp>
  32. #include <boost/intrusive_ptr.hpp>
  33. #include <boost/function.hpp>
  34. #include <boost/bind.hpp>
  35. #ifdef BOOST_HAS_THREADS
  36. # include <boost/thread/thread.hpp>
  37. #endif
  38. #include <iostream>
  39. #include <ctime>
  40. #ifdef BOOST_NO_STDC_NAMESPACE
  41. namespace std
  42. {
  43. using ::clock_t;
  44. using ::clock;
  45. }
  46. #endif
  47. #ifdef BOOST_INTEL
  48. # pragma warning( disable: 304 ) // access control not specified
  49. # pragma warning( disable: 383 ) // reference to temporary used
  50. # pragma warning( disable: 981 ) // operands are evaluated in unspecified order
  51. #endif
  52. namespace sc = boost::statechart;
  53. //////////////////////////////////////////////////////////////////////////////
  54. const unsigned int noOfEvents = 1000000;
  55. //////////////////////////////////////////////////////////////////////////////
  56. char GetKey()
  57. {
  58. char key;
  59. std::cin >> key;
  60. return key;
  61. }
  62. //////////////////////////////////////////////////////////////////////////////
  63. int main()
  64. {
  65. std::cout << "Boost.Statechart PingPong example\n\n";
  66. std::cout << "Threading configuration:\n";
  67. #ifdef BOOST_HAS_THREADS
  68. std::cout << "Multi-threaded build with ";
  69. #ifdef USE_TWO_THREADS
  70. std::cout << 2;
  71. #else
  72. std::cout << 1;
  73. #endif
  74. std::cout << " thread(s).\n";
  75. #else
  76. std::cout << "Single-threaded build\n";
  77. #endif
  78. std::cout << "\np<CR>: Performance test\n";
  79. std::cout << "e<CR>: Exits the program\n\n";
  80. char key = GetKey();
  81. while ( key != 'e' )
  82. {
  83. switch( key )
  84. {
  85. case 'p':
  86. {
  87. #ifdef BOOST_HAS_THREADS
  88. MyScheduler scheduler1( true );
  89. #else
  90. MyScheduler scheduler1;
  91. #endif
  92. #ifdef USE_TWO_THREADS
  93. #ifdef BOOST_HAS_THREADS
  94. MyScheduler scheduler2( true );
  95. #else
  96. MyScheduler & scheduler2 = scheduler1;
  97. #endif
  98. #else
  99. MyScheduler & scheduler2 = scheduler1;
  100. #endif
  101. MyScheduler::processor_handle player1 =
  102. scheduler1.create_processor< Player >( noOfEvents / 2 );
  103. scheduler1.initiate_processor( player1 );
  104. MyScheduler::processor_handle player2 =
  105. scheduler2.create_processor< Player >( noOfEvents / 2 );
  106. scheduler2.initiate_processor( player2 );
  107. boost::intrusive_ptr< BallReturned > pInitialBall = new BallReturned();
  108. pInitialBall->returnToOpponent = boost::bind(
  109. &MyScheduler::queue_event, &scheduler1, player1, _1 );
  110. pInitialBall->abortGame = boost::bind(
  111. &MyScheduler::queue_event,
  112. &scheduler1, player1, MakeIntrusive( new GameAborted() ) );
  113. scheduler2.queue_event( player2, pInitialBall );
  114. std::cout << "\nHaving players return the ball " <<
  115. noOfEvents << " times. Please wait...\n";
  116. const unsigned int prevCount = Player::TotalNoOfProcessedEvents();
  117. const std::clock_t startTime = std::clock();
  118. #ifdef USE_TWO_THREADS
  119. #ifdef BOOST_HAS_THREADS
  120. boost::thread otherThread(
  121. boost::bind( &MyScheduler::operator(), &scheduler2, 0 ) );
  122. scheduler1();
  123. otherThread.join();
  124. #else
  125. scheduler1();
  126. #endif
  127. #else
  128. scheduler1();
  129. #endif
  130. const std::clock_t elapsedTime = std::clock() - startTime;
  131. std::cout << "Time to send and dispatch one event and\n" <<
  132. "perform the resulting transition: ";
  133. std::cout << elapsedTime / static_cast< double >( CLOCKS_PER_SEC ) *
  134. 1000000.0 / ( Player::TotalNoOfProcessedEvents() - prevCount )
  135. << " microseconds\n\n";
  136. }
  137. break;
  138. default:
  139. {
  140. std::cout << "Invalid key!\n";
  141. }
  142. }
  143. key = GetKey();
  144. }
  145. return 0;
  146. }