OpenWalnut
1.2.5
|
00001 //--------------------------------------------------------------------------- 00002 // 00003 // Project: OpenWalnut ( http://www.openwalnut.org ) 00004 // 00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS 00006 // For more information see http://www.openwalnut.org/copying 00007 // 00008 // This file is part of OpenWalnut. 00009 // 00010 // OpenWalnut is free software: you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as published by 00012 // the Free Software Foundation, either version 3 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // OpenWalnut is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public License 00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>. 00022 // 00023 //--------------------------------------------------------------------------- 00024 00025 #ifndef WTHREADEDFUNCTION_TEST_H 00026 #define WTHREADEDFUNCTION_TEST_H 00027 00028 #include <string> 00029 00030 #include <cxxtest/TestSuite.h> 00031 00032 #include "../WThreadedFunction.h" 00033 #include "../WSharedObject.h" 00034 00035 /** 00036 * \class WThreadedFunctionTest 00037 * 00038 * Tests the WThreadedFunction class. 00039 */ 00040 class WThreadedFunctionTest : public CxxTest::TestSuite 00041 { 00042 /** 00043 * A threaded function. 00044 */ 00045 class FuncType 00046 { 00047 public: 00048 /** 00049 * Constructor, initialize some stuff. 00050 * 00051 * \param value An int value. 00052 */ 00053 FuncType( int value ) // NOLINT 00054 : m_input( new int( value ) ) // NOLINT 00055 { 00056 // init stuff here 00057 m_result.getWriteTicket()->get() = 0; 00058 m_stopped.getWriteTicket()->get() = false; 00059 00060 if( value < 0 ) 00061 { 00062 value = -value; 00063 } 00064 } 00065 00066 /** 00067 * This is the actual thread function. 00068 * 00069 * \param shutdown A flag indicating the thread is supposed to stop. 00070 */ 00071 void operator() ( std::size_t, std::size_t, WBoolFlag const& shutdown ) 00072 { 00073 for( int i = 1; i <= *m_input.get() && !shutdown(); ++i ) 00074 { 00075 m_result.getWriteTicket()->get() += i; 00076 } 00077 if( shutdown() ) 00078 { 00079 m_stopped.getWriteTicket()->get() = true; 00080 } 00081 sleep( 1 ); 00082 } 00083 00084 /** 00085 * Check if the thread was ordered to stop. 00086 * 00087 * \return true, if the thread was ordered to stop 00088 */ 00089 bool stopped() 00090 { 00091 return m_stopped.getReadTicket()->get(); 00092 } 00093 00094 /** 00095 * A method to extract the result. 00096 * 00097 * \return The result of the threaded computation. 00098 */ 00099 int getResult() 00100 { 00101 return m_result.getReadTicket()->get(); 00102 } 00103 00104 /** 00105 * Reset everything. 00106 */ 00107 void reset() 00108 { 00109 m_result.getWriteTicket()->get() = 0; 00110 } 00111 00112 private: 00113 00114 //! the input data 00115 boost::shared_ptr< int const > m_input; 00116 00117 //! the result 00118 WSharedObject< int > m_result; 00119 00120 //! thread stopped? 00121 WSharedObject< bool > m_stopped; 00122 }; 00123 00124 /** 00125 * A function that throws exceptions. 00126 */ 00127 class ExceptionalFuncType 00128 { 00129 public: 00130 /** 00131 * The function. 00132 */ 00133 void operator() ( std::size_t, std::size_t, WBoolFlag& ) 00134 { 00135 throw WException( std::string( "Test!" ) ); 00136 } 00137 }; 00138 00139 public: 00140 /** 00141 * A function computed by multiple threads should correctly set 00142 * its status and compute the correct results. 00143 */ 00144 void testMultipleThreads() 00145 { 00146 boost::shared_ptr< FuncType > func( new FuncType( 5 ) ); 00147 // test 1 thread 00148 { 00149 WThreadedFunction< FuncType > f( 1, func ); 00150 00151 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00152 f.run(); 00153 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00154 f.wait(); 00155 TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED ); 00156 00157 TS_ASSERT_EQUALS( func->getResult(), 15 ); 00158 func->reset(); 00159 00160 f.run(); 00161 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00162 f.wait(); 00163 00164 TS_ASSERT_EQUALS( func->getResult(), 15 ); 00165 00166 f.run(); 00167 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00168 f.wait(); 00169 00170 TS_ASSERT_EQUALS( func->getResult(), 30 ); 00171 func->reset(); 00172 } 00173 // test 2 threads 00174 { 00175 WThreadedFunction< FuncType > f( 2, func ); 00176 00177 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00178 f.run(); 00179 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00180 f.wait(); 00181 TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED ); 00182 00183 TS_ASSERT_EQUALS( func->getResult(), 30 ); 00184 func->reset(); 00185 } 00186 // test 5 threads 00187 { 00188 WThreadedFunction< FuncType > f( 5, func ); 00189 00190 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00191 f.run(); 00192 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00193 f.wait(); 00194 TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED ); 00195 00196 TS_ASSERT_EQUALS( func->getResult(), 75 ); 00197 func->reset(); 00198 } 00199 } 00200 00201 /** 00202 * Status should be set correctly when threads are ordered to stop. 00203 */ 00204 void testStopThreads() 00205 { 00206 boost::shared_ptr< FuncType > func( new FuncType( 100000000 ) ); 00207 WThreadedFunction< FuncType > f( 6, func ); 00208 00209 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00210 f.run(); 00211 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00212 f.stop(); 00213 TS_ASSERT_EQUALS( f.status(), W_THREADS_STOP_REQUESTED ); 00214 f.wait(); 00215 TS_ASSERT_EQUALS( f.status(), W_THREADS_ABORTED ); 00216 00217 TS_ASSERT( func->stopped() ); 00218 func->reset(); 00219 } 00220 00221 /** 00222 * The stop condition should be notified correctly. 00223 */ 00224 void testStopCondition() 00225 { 00226 boost::shared_ptr< FuncType > func( new FuncType( 5 ) ); 00227 WThreadedFunction< FuncType > f( 6, func ); 00228 00229 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00230 f.run(); 00231 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00232 f.getThreadsDoneCondition()->wait(); 00233 TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED ); 00234 00235 TS_ASSERT_EQUALS( func->getResult(), 90 ); 00236 func->reset(); 00237 } 00238 00239 /** 00240 * Exceptions should lead to the status beeing changed to W_THREADS_ABORTED. Also, 00241 * exceptions should be forwarded to the exception handler. 00242 */ 00243 void testExceptionHandling() 00244 { 00245 boost::shared_ptr< ExceptionalFuncType > func( new ExceptionalFuncType ); 00246 WThreadedFunction< ExceptionalFuncType > f( 7, func ); 00247 f.subscribeExceptionSignal( boost::bind( &WThreadedFunctionTest::handleException, this, _1 ) ); 00248 00249 m_exceptionCounter.getWriteTicket()->get() = 0; 00250 00251 f.run(); 00252 f.wait(); 00253 00254 TS_ASSERT_EQUALS( f.status(), W_THREADS_ABORTED ); 00255 TS_ASSERT_EQUALS( m_exceptionCounter.getReadTicket()->get(), 7 ); 00256 } 00257 00258 private: 00259 /** 00260 * Exception callback. 00261 */ 00262 void handleException( WException const& ) 00263 { 00264 ++m_exceptionCounter.getWriteTicket()->get(); 00265 } 00266 00267 //! a counter 00268 WSharedObject< int > m_exceptionCounter; 00269 }; 00270 00271 #endif // WTHREADEDFUNCTION_TEST_H