OpenWalnut
1.4.0
|
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 //! the input data 00114 boost::shared_ptr< int const > m_input; 00115 00116 //! the result 00117 WSharedObject< int > m_result; 00118 00119 //! thread stopped? 00120 WSharedObject< bool > m_stopped; 00121 }; 00122 00123 /** 00124 * A function that throws exceptions. 00125 */ 00126 class ExceptionalFuncType 00127 { 00128 public: 00129 /** 00130 * The function. 00131 */ 00132 void operator() ( std::size_t, std::size_t, WBoolFlag& ) 00133 { 00134 throw WException( std::string( "Test!" ) ); 00135 } 00136 }; 00137 00138 public: 00139 /** 00140 * A function computed by multiple threads should correctly set 00141 * its status and compute the correct results. 00142 */ 00143 void testMultipleThreads() 00144 { 00145 boost::shared_ptr< FuncType > func( new FuncType( 5 ) ); 00146 // test 1 thread 00147 { 00148 WThreadedFunction< FuncType > f( 1, func ); 00149 00150 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00151 f.run(); 00152 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00153 f.wait(); 00154 TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED ); 00155 00156 TS_ASSERT_EQUALS( func->getResult(), 15 ); 00157 func->reset(); 00158 00159 f.run(); 00160 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00161 f.wait(); 00162 00163 TS_ASSERT_EQUALS( func->getResult(), 15 ); 00164 00165 f.run(); 00166 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00167 f.wait(); 00168 00169 TS_ASSERT_EQUALS( func->getResult(), 30 ); 00170 func->reset(); 00171 } 00172 // test 2 threads 00173 { 00174 WThreadedFunction< FuncType > f( 2, func ); 00175 00176 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00177 f.run(); 00178 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00179 f.wait(); 00180 TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED ); 00181 00182 TS_ASSERT_EQUALS( func->getResult(), 30 ); 00183 func->reset(); 00184 } 00185 // test 5 threads 00186 { 00187 WThreadedFunction< FuncType > f( 5, func ); 00188 00189 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00190 f.run(); 00191 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00192 f.wait(); 00193 TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED ); 00194 00195 TS_ASSERT_EQUALS( func->getResult(), 75 ); 00196 func->reset(); 00197 } 00198 } 00199 00200 /** 00201 * Status should be set correctly when threads are ordered to stop. 00202 */ 00203 void testStopThreads() 00204 { 00205 boost::shared_ptr< FuncType > func( new FuncType( 100000000 ) ); 00206 WThreadedFunction< FuncType > f( 6, func ); 00207 00208 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00209 f.run(); 00210 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00211 f.stop(); 00212 TS_ASSERT_EQUALS( f.status(), W_THREADS_STOP_REQUESTED ); 00213 f.wait(); 00214 TS_ASSERT_EQUALS( f.status(), W_THREADS_ABORTED ); 00215 00216 TS_ASSERT( func->stopped() ); 00217 func->reset(); 00218 } 00219 00220 /** 00221 * The stop condition should be notified correctly. 00222 */ 00223 void testStopCondition() 00224 { 00225 boost::shared_ptr< FuncType > func( new FuncType( 5 ) ); 00226 WThreadedFunction< FuncType > f( 6, func ); 00227 00228 TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED ); 00229 f.run(); 00230 TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING ); 00231 f.getThreadsDoneCondition()->wait(); 00232 TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED ); 00233 00234 TS_ASSERT_EQUALS( func->getResult(), 90 ); 00235 func->reset(); 00236 } 00237 00238 /** 00239 * Exceptions should lead to the status beeing changed to W_THREADS_ABORTED. Also, 00240 * exceptions should be forwarded to the exception handler. 00241 */ 00242 void testExceptionHandling() 00243 { 00244 boost::shared_ptr< ExceptionalFuncType > func( new ExceptionalFuncType ); 00245 WThreadedFunction< ExceptionalFuncType > f( 7, func ); 00246 f.subscribeExceptionSignal( boost::bind( &WThreadedFunctionTest::handleException, this, _1 ) ); 00247 00248 m_exceptionCounter.getWriteTicket()->get() = 0; 00249 00250 f.run(); 00251 f.wait(); 00252 00253 TS_ASSERT_EQUALS( f.status(), W_THREADS_ABORTED ); 00254 TS_ASSERT_EQUALS( m_exceptionCounter.getReadTicket()->get(), 7 ); 00255 } 00256 00257 private: 00258 /** 00259 * Exception callback. 00260 */ 00261 void handleException( WException const& ) 00262 { 00263 ++m_exceptionCounter.getWriteTicket()->get(); 00264 } 00265 00266 //! a counter 00267 WSharedObject< int > m_exceptionCounter; 00268 }; 00269 00270 #endif // WTHREADEDFUNCTION_TEST_H