OpenWalnut 1.2.5
WThreadedFunction_test.h
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
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends