examples/ForumNokia/ThreadExample/src/threadengine.cpp

00001 /*
00002 * ============================================================================
00003 *  Name     : CThreadEngine from CThreadEngine.h
00004 *  Part of  : Thread
00005 *  Created  : 04.02.2005 by Forum Nokia
00006 *  Version  : 1.0
00007 *  Copyright: Nokia Corporation
00008 * ============================================================================
00009 */
00010 
00011 // INCLUDES
00012 #include "..\inc\threadengine.h"
00013 #include "threadappview.h"
00014 #include "threadanimation.h"
00015 #include <thread.rsg>
00016 #include <StringLoader.h> 
00017 
00018 // time that threads sleep in ThreadFunction
00019 const TInt KThreadUpdateInterval = 200000;
00020 
00021 // resurrect threads after this interval
00022 const TInt KThreadWatchdogInterval = 5000000;
00023 
00024 // ----------------------------------------------------------------------------
00025 // CThreadEngine::CThreadEngine(void)
00026 //
00027 // constructor
00028 // ----------------------------------------------------------------------------
00029 CThreadEngine::CThreadEngine(void): CTimer(CActive::EPriorityStandard), iNotSynchonizedCounter(0), 
00030         iSynchronizedCounter(0), iCreatedThreads(EFalse)
00031         {
00032         // Create a mutex for synchronization purpose
00033         iMutex.CreateLocal();
00034 
00035         }
00036 
00037 // ----------------------------------------------------------------------------
00038 // CThreadEngine::~CThreadEngine(void)
00039 //
00040 // destructor
00041 // ----------------------------------------------------------------------------
00042 CThreadEngine::~CThreadEngine(void)
00043         {       
00044         // Kill all threads before closing the handles
00045         iThreadOne.Kill(KErrNone);
00046         iThreadTwo.Kill(KErrNone);
00047         iThreadThree.Kill(KErrNone);
00048                 
00049         // Handles should be closed
00050         iThreadOne.Close();
00051         iThreadTwo.Close();
00052         iThreadThree.Close();   
00053         }
00054 
00055 
00056 CThreadEngine* CThreadEngine::NewL(CThreadAppView* aView)
00057         {
00058         CThreadEngine* self = CThreadEngine::NewLC(aView);
00059         CleanupStack::Pop(self);
00060         return self;
00061         }
00062 
00063 CThreadEngine* CThreadEngine::NewLC(CThreadAppView* aView)
00064         {
00065         CThreadEngine* self = new (ELeave) CThreadEngine;
00066         CleanupStack::PushL(self);
00067         self->ConstructL(aView);
00068         return self;
00069         }
00070 
00071 // Standard EPOC 2nd phase constructor
00072 void CThreadEngine::ConstructL(CThreadAppView* aView)
00073         {
00074         CTimer::ConstructL();
00075 
00076         iView = aView;
00077         CActiveScheduler::Add( this );
00078         }
00079 
00080 // ----------------------------------------------------------------------------
00081 // CThreadEngine::StartL()
00082 //
00083 // Create threads and start Timer that resurrects threads. 
00084 // ----------------------------------------------------------------------------
00085 void CThreadEngine::StartL()
00086         {
00087         // Create threads only once
00088         if ( iCreatedThreads == EFalse )
00089                 {
00090                 CreateThreadsL();
00091                 After( KThreadWatchdogInterval );
00092                 }
00093         }
00094 
00095 // ----------------------------------------------------------------------------
00096 // CThreadEngine::RunL()
00097 //
00098 // Check that all threads are alive, if not then create and resume them again.
00099 // After resuming, continue the thread animation.
00100 // Called by the active scheduler when a request completion event occurs.
00101 // ExitType can be used to check thread state ( killed / panicked / alive )
00102 // ----------------------------------------------------------------------------
00103 void CThreadEngine::RunL()
00104         {
00105 
00106         // Has thread one been killed?
00107         if ( iThreadOne.ExitType() == EExitKill ) 
00108                 {
00109                 HBufC* threadWasKilled = StringLoader::LoadLC( R_THREAD1_WAS_KILLED );
00110                 iView->DrawText( *threadWasKilled );
00111                 CleanupStack::PopAndDestroy( threadWasKilled );
00112                 
00113                 // Closing the handle finalises thread deconstructing. Thread with
00114                 // same name can be opened aftewards. Without closing the handle new unique
00115                 // name must be used. 
00116                 iThreadOne.Close();
00117 
00118                 // Create a new thread because earlier was killed
00119                 if ( iThreadOne.Create( _L("thread1"), ExecuteThreadOne, 4096, KMinHeapSize, 
00120                          256*KMinHeapSize, &iNotSynchonizedCounter) != KErrNone )
00121                         {
00122                         // Create failed. This should not happen.
00123                         HBufC* threadCreateFailureText = StringLoader::LoadLC( R_THREAD1_CREATE_FAILURE );
00124                         iView->DrawText( *threadCreateFailureText );
00125                         CleanupStack::PopAndDestroy( threadCreateFailureText);
00126                         }
00127                 else 
00128                         {       
00129                         // Start newly created thread
00130                         iThreadOne.Resume();
00131                         // Start the threadOne animation
00132                         iView->iAnimationOne->StartAnimationL();
00133                         }               
00134                 }
00135 
00136         // Has thread two been killed?
00137         if ( iThreadTwo.ExitType() == EExitKill ) 
00138                 {
00139                 HBufC* threadWasKilled = StringLoader::LoadLC( R_THREAD2_WAS_KILLED );
00140                 iView->DrawText( *threadWasKilled );
00141                 CleanupStack::PopAndDestroy( threadWasKilled );
00142 
00143                 iThreadTwo.Close();
00144 
00145                 // Create a new thread because earlier was killed
00146                 if ( KErrNone != iThreadTwo.Create( _L("thread2") , ExecuteThreadTwo, 4096, KMinHeapSize, 
00147                          256*KMinHeapSize, this ) )
00148                         {
00149                         // Create failed. This should not happen.
00150                         HBufC* threadCreateFailureText = StringLoader::LoadLC( R_THREAD2_CREATE_FAILURE );
00151                         iView->DrawText( *threadCreateFailureText );
00152                         CleanupStack::PopAndDestroy( threadCreateFailureText);
00153                         }
00154                 else 
00155                         {
00156                         // Start newly created thread
00157                         iThreadTwo.Resume();
00158                         iView->iAnimationTwo->StartAnimationL();
00159                         }
00160                 }
00161                 
00162         // Has thread three been killed?
00163         if ( iThreadThree.ExitType() == EExitKill ) 
00164                 {
00165                 HBufC* threadWasKilled = StringLoader::LoadLC( R_THREAD3_WAS_KILLED );
00166                 iView->DrawText( *threadWasKilled );
00167                 CleanupStack::PopAndDestroy( threadWasKilled );
00168 
00169                 iThreadThree.Close();
00170 
00171                 // Create a new thread because earlier was killed
00172                 if ( KErrNone != iThreadThree.Create( _L("thread3") , ExecuteThreadThree, 4096, KMinHeapSize, 
00173                          256*KMinHeapSize, this) ) 
00174                         {
00175                         // Create failed. This should not happen.
00176                         HBufC* threadCreateFailureText = StringLoader::LoadLC( R_THREAD1_CREATE_FAILURE );
00177                         iView->DrawText( *threadCreateFailureText );
00178                         CleanupStack::PopAndDestroy( threadCreateFailureText );
00179                         }
00180                 else 
00181                         {
00182                         // Start newly created thread
00183                         iThreadThree.Resume();
00184                         iView->iAnimationThree->StartAnimationL();
00185                         }
00186                 }
00187  
00188         // Wait for a while and run the same function again 
00189         After( KThreadWatchdogInterval );
00190         }
00191 
00192 // ----------------------------------------------------------------------------
00193 // CThreadEngine::DoCancel()
00194 //
00195 // Cancel and stop the timer. 
00196 // ----------------------------------------------------------------------------
00197 void CThreadEngine::DoCancel()
00198         {
00199         Cancel();
00200         }
00201 
00202 // ----------------------------------------------------------------------------
00203 // CThreadEngine::RunError(TInt)
00204 //
00205 // Cancel and stop the timer. 
00206 // ----------------------------------------------------------------------------
00207 TInt CThreadEngine::RunError(TInt)
00208         {
00209         return KErrNone;
00210         }
00211 
00212 // ----------------------------------------------------------------------------
00213 // CThreadEngine::ThreadKilledText(const TDesC& aText, TInt aCount)
00214 //
00215 // Print text and a number after thread has been killed. Count reflects 
00216 // how long thread was running. TempValue is needed for TInt to TDesC 
00217 // conversion
00218 // ----------------------------------------------------------------------------
00219 void CThreadEngine::ThreadKilledText(const TDesC& aText, TInt aCount)
00220         {
00221         TBuf<50> tempBuf;
00222 
00223         tempBuf.Append( aText );
00224         tempBuf.AppendNum( aCount );
00225         iView->DrawText( tempBuf );     
00226         }
00227 
00228 // ----------------------------------------------------------------------------
00229 // CThreadEngine::KillThread(TInt aThreadCount)
00230 //
00231 // Kill threadOne (1) / threadTwo (2) / threadThree (3)
00232 // and draw text that a thread has been killed. Stops animation
00233 // after killing. Resets counters.
00234 // ----------------------------------------------------------------------------
00235 void CThreadEngine::KillThread(TInt aThreadCount)
00236         {
00237         //Do not kill before threads have been created
00238         if ( iCreatedThreads == EFalse )
00239                 {
00240                 return;
00241                 }
00242 
00243         HBufC* killedText;
00244 
00245         switch( aThreadCount )
00246                 {
00247                 case 1:
00248                         // Thread can be killed because handle is connected to it.
00249                         iThreadOne.Kill(KErrNone);
00250 
00251                         killedText = StringLoader::LoadLC(R_KILLED_THREAD1);
00252                         ThreadKilledText( *killedText, iNotSynchonizedCounter);
00253                         CleanupStack::PopAndDestroy(killedText);
00254 
00255                         iNotSynchonizedCounter = 0;
00256 
00257                         iView->iAnimationOne->StopAnimation();
00258                         
00259                 break;
00260                 case 2:
00261                         iThreadTwo.Kill(KErrNone);
00262 
00263                         killedText = StringLoader::LoadLC(R_KILLED_THREAD2);
00264                         ThreadKilledText( *killedText, iSynchronizedCounter);
00265                         CleanupStack::PopAndDestroy(killedText);
00266 
00267                         // Reset counter
00268                         SetSyncValue(0);
00269                         
00270                         iView->iAnimationTwo->StopAnimation();
00271 
00272                 break;
00273                 case 3:
00274                         iThreadThree.Kill(KErrNone);
00275 
00276                         killedText = StringLoader::LoadLC(R_KILLED_THREAD3);
00277                         ThreadKilledText( *killedText, iSynchronizedCounter );
00278                         CleanupStack::PopAndDestroy( killedText );
00279 
00280                         // Reset counter
00281                         SetSyncValue(0);
00282                         
00283                         iView->iAnimationThree->StopAnimation();
00284                 break;
00285                 }
00286         }
00287 
00288 // ----------------------------------------------------------------------------
00289 // CThreadEngine::ExecuteThread(TAny *aPtr)
00290 //
00291 // Threadfunction of threadOne. Executed only by threadOne.
00292 // ----------------------------------------------------------------------------
00293 TInt CThreadEngine::ExecuteThreadOne(TAny *aPtr)
00294         {
00295         // Convert pointer
00296         TInt* notSync = static_cast<TInt*>(aPtr);
00297         
00298         TBool loopConditionOne = ETrue;
00299         while ( loopConditionOne )
00300                 {
00301                 // iNotSynchonizedCounter++, synhronization is not needed because
00302                 // only this thread changes iNotSynchronizedCount value.
00303                 *notSync = *notSync + 1;
00304                 // Wait for a while
00305                 User::After( KThreadUpdateInterval );
00306                 }
00307 
00308         return KErrNone;
00309         }
00310 
00311 // ----------------------------------------------------------------------------
00312 // CThreadEngine::ExecuteThreadTwo(TAny *aPtr)
00313 //
00314 // Threadfunction of threadTwo. Executed only by threadTwo.
00315 // ----------------------------------------------------------------------------
00316 TInt CThreadEngine::ExecuteThreadTwo(TAny *aPtr)
00317         {
00318         // Convert pointer
00319         CThreadEngine* engine = static_cast<CThreadEngine*>(aPtr);
00320         
00321         TBool loopConditionTwo = ETrue;
00322         while ( loopConditionTwo )
00323                 {
00324                 // iSynchronizedCounter++;
00325                 // The counter is not handled directly, because two threads
00326                 // interact with the same variable. Synchronization is needed.
00327                 engine->SetSyncValue(engine->GetSyncValue()+1);
00328                 User::After( KThreadUpdateInterval );
00329                 }
00330 
00331         return KErrNone;
00332         }
00333 
00334 // ----------------------------------------------------------------------------
00335 // CThreadEngine::ExecuteThreadThree(TAny *aPtr)
00336 //
00337 // Threadfunction of threadThree. Executed only by threadThree.
00338 // ----------------------------------------------------------------------------
00339 TInt CThreadEngine::ExecuteThreadThree(TAny *aPtr)
00340         {
00341         CThreadEngine* engine = static_cast<CThreadEngine*>(aPtr);
00342 
00343         TBool loopConditionThree = ETrue;
00344         while ( loopConditionThree )
00345                 {
00346                 // iSynchronizedCounter++;
00347                 // The counter is not handled directly, because two threads
00348                 // interact with the same variable. Synchronization is needed.
00349                 engine->SetSyncValue(engine->GetSyncValue()+1);
00350                 User::After( KThreadUpdateInterval );
00351                 }
00352 
00353         return KErrNone;
00354         }
00355 
00356 // ----------------------------------------------------------------------------
00357 // CThreadEngine::SetSyncValue(TInt aValue)
00358 //
00359 // Set the iSynchronizedCounter value. Synchronization is implemented by using
00360 // a semaphore. Function is thread-safe.
00361 // ----------------------------------------------------------------------------
00362 void CThreadEngine::SetSyncValue(TInt aValue)
00363         {
00364         iMutex.Wait();
00365         iSynchronizedCounter = aValue;
00366         iMutex.Signal();
00367         }
00368 
00369 // ----------------------------------------------------------------------------
00370 // CThreadEngine::GetSyncValue() const
00371 //
00372 // Returns iSynchronizedCounter. 
00373 // 
00374 // ----------------------------------------------------------------------------
00375 TInt CThreadEngine::GetSyncValue() const
00376         {
00377         return iSynchronizedCounter;
00378         }
00379 
00380 // ----------------------------------------------------------------------------
00381 // CThreadEngine::CreateThreadsL()
00382 //
00383 // Create three threads and resume them. Start thread animations.
00384 // 
00385 // ----------------------------------------------------------------------------
00386 void CThreadEngine::CreateThreadsL()
00387         {
00388         //Create thread1
00389         iThreadOne.Create( _L("thread1") , ExecuteThreadOne, 4096, KMinHeapSize, 256*KMinHeapSize, 
00390                 &iNotSynchonizedCounter);
00391         iThreadOne.Resume();
00392         iView->iAnimationOne->StartAnimationL();
00393 
00394         // Create thread2
00395         // thread two and three modify same counter, that is why a pointer to this class is given,
00396         // not the counter itself. Threads modify iSynchronizedCounter through two CThreadEngine 
00397         // functions: GetSyncValue() / SetSyncValue(). Thread2 gets a pointer to CThreadEngine,
00398         // because it must use synchronized funtions to increment the counter.
00399         iThreadTwo.Create( _L("thread2") , ExecuteThreadTwo, 4096, KMinHeapSize, 256*KMinHeapSize,
00400                 this);  
00401         iThreadTwo.Resume();
00402         iView->iAnimationTwo->StartAnimationL();
00403 
00404         //Create thread3
00405         iThreadThree.Create(_L("thread3") , ExecuteThreadThree, 4096, KMinHeapSize, 256*KMinHeapSize,
00406                 this );
00407         iThreadThree.Resume();
00408         iView->iAnimationThree->StartAnimationL();
00409 
00410         // All threads have been now created. Threads can be killed.
00411         iCreatedThreads = ETrue;        
00412         }

Generated by  doxygen 1.6.2