📄 threadengine.cpp
字号:
/*
* ============================================================================
* Name : CThreadEngine from CThreadEngine.h
* Part of : Thread
* Created : 04.02.2005 by Forum Nokia
* Version : 1.0
* Copyright: Nokia Corporation
* ============================================================================
*/
// INCLUDES
#include "..\inc\threadengine.h"
#include "threadappview.h"
#include "threadanimation.h"
#include <thread.rsg>
#include <StringLoader.h>
// time that threads sleep in ThreadFunction
const TInt KThreadUpdateInterval = 200000;
// resurrect threads after this interval
const TInt KThreadWatchdogInterval = 5000000;
// ----------------------------------------------------------------------------
// CThreadEngine::CThreadEngine(void)
//
// constructor
// ----------------------------------------------------------------------------
CThreadEngine::CThreadEngine(void): CTimer(CActive::EPriorityStandard), iNotSynchonizedCounter(0),
iSynchronizedCounter(0), iCreatedThreads(EFalse)
{
// Create a mutex for synchronization purpose
iMutex.CreateLocal();
}
// ----------------------------------------------------------------------------
// CThreadEngine::~CThreadEngine(void)
//
// destructor
// ----------------------------------------------------------------------------
CThreadEngine::~CThreadEngine(void)
{
// Kill all threads before closing the handles
iThreadOne.Kill(KErrNone);
iThreadTwo.Kill(KErrNone);
iThreadThree.Kill(KErrNone);
// Handles should be closed
iThreadOne.Close();
iThreadTwo.Close();
iThreadThree.Close();
}
CThreadEngine* CThreadEngine::NewL(CThreadAppView* aView)
{
CThreadEngine* self = CThreadEngine::NewLC(aView);
CleanupStack::Pop(self);
return self;
}
CThreadEngine* CThreadEngine::NewLC(CThreadAppView* aView)
{
CThreadEngine* self = new (ELeave) CThreadEngine;
CleanupStack::PushL(self);
self->ConstructL(aView);
return self;
}
// Standard EPOC 2nd phase constructor
void CThreadEngine::ConstructL(CThreadAppView* aView)
{
CTimer::ConstructL();
iView = aView;
CActiveScheduler::Add( this );
}
// ----------------------------------------------------------------------------
// CThreadEngine::StartL()
//
// Create threads and start Timer that resurrects threads.
// ----------------------------------------------------------------------------
void CThreadEngine::StartL()
{
// Create threads only once
if ( iCreatedThreads == EFalse )
{
CreateThreadsL();
After( KThreadWatchdogInterval );
}
}
// ----------------------------------------------------------------------------
// CThreadEngine::RunL()
//
// Check that all threads are alive, if not then create and resume them again.
// After resuming, continue the thread animation.
// Called by the active scheduler when a request completion event occurs.
// ExitType can be used to check thread state ( killed / panicked / alive )
// ----------------------------------------------------------------------------
void CThreadEngine::RunL()
{
// Has thread one been killed?
if ( iThreadOne.ExitType() == EExitKill )
{
HBufC* threadWasKilled = StringLoader::LoadLC( R_THREAD1_WAS_KILLED );
iView->DrawText( *threadWasKilled );
CleanupStack::PopAndDestroy( threadWasKilled );
// Closing the handle finalises thread deconstructing. Thread with
// same name can be opened aftewards. Without closing the handle new unique
// name must be used.
iThreadOne.Close();
// Create a new thread because earlier was killed
if ( iThreadOne.Create( _L("thread1"), ExecuteThreadOne, 4096, KMinHeapSize,
256*KMinHeapSize, &iNotSynchonizedCounter) != KErrNone )
{
// Create failed. This should not happen.
HBufC* threadCreateFailureText = StringLoader::LoadLC( R_THREAD1_CREATE_FAILURE );
iView->DrawText( *threadCreateFailureText );
CleanupStack::PopAndDestroy( threadCreateFailureText);
}
else
{
// Start newly created thread
iThreadOne.Resume();
// Start the threadOne animation
iView->iAnimationOne->StartAnimationL();
}
}
// Has thread two been killed?
if ( iThreadTwo.ExitType() == EExitKill )
{
HBufC* threadWasKilled = StringLoader::LoadLC( R_THREAD2_WAS_KILLED );
iView->DrawText( *threadWasKilled );
CleanupStack::PopAndDestroy( threadWasKilled );
iThreadTwo.Close();
// Create a new thread because earlier was killed
if ( KErrNone != iThreadTwo.Create( _L("thread2") , ExecuteThreadTwo, 4096, KMinHeapSize,
256*KMinHeapSize, this ) )
{
// Create failed. This should not happen.
HBufC* threadCreateFailureText = StringLoader::LoadLC( R_THREAD2_CREATE_FAILURE );
iView->DrawText( *threadCreateFailureText );
CleanupStack::PopAndDestroy( threadCreateFailureText);
}
else
{
// Start newly created thread
iThreadTwo.Resume();
iView->iAnimationTwo->StartAnimationL();
}
}
// Has thread three been killed?
if ( iThreadThree.ExitType() == EExitKill )
{
HBufC* threadWasKilled = StringLoader::LoadLC( R_THREAD3_WAS_KILLED );
iView->DrawText( *threadWasKilled );
CleanupStack::PopAndDestroy( threadWasKilled );
iThreadThree.Close();
// Create a new thread because earlier was killed
if ( KErrNone != iThreadThree.Create( _L("thread3") , ExecuteThreadThree, 4096, KMinHeapSize,
256*KMinHeapSize, this) )
{
// Create failed. This should not happen.
HBufC* threadCreateFailureText = StringLoader::LoadLC( R_THREAD1_CREATE_FAILURE );
iView->DrawText( *threadCreateFailureText );
CleanupStack::PopAndDestroy( threadCreateFailureText );
}
else
{
// Start newly created thread
iThreadThree.Resume();
iView->iAnimationThree->StartAnimationL();
}
}
// Wait for a while and run the same function again
After( KThreadWatchdogInterval );
}
// ----------------------------------------------------------------------------
// CThreadEngine::DoCancel()
//
// Cancel and stop the timer.
// ----------------------------------------------------------------------------
void CThreadEngine::DoCancel()
{
Cancel();
}
// ----------------------------------------------------------------------------
// CThreadEngine::RunError(TInt)
//
// Cancel and stop the timer.
// ----------------------------------------------------------------------------
TInt CThreadEngine::RunError(TInt)
{
return KErrNone;
}
// ----------------------------------------------------------------------------
// CThreadEngine::ThreadKilledText(const TDesC& aText, TInt aCount)
//
// Print text and a number after thread has been killed. Count reflects
// how long thread was running. TempValue is needed for TInt to TDesC
// conversion
// ----------------------------------------------------------------------------
void CThreadEngine::ThreadKilledText(const TDesC& aText, TInt aCount)
{
TBuf<50> tempBuf;
tempBuf.Append( aText );
tempBuf.AppendNum( aCount );
iView->DrawText( tempBuf );
}
// ----------------------------------------------------------------------------
// CThreadEngine::KillThread(TInt aThreadCount)
//
// Kill threadOne (1) / threadTwo (2) / threadThree (3)
// and draw text that a thread has been killed. Stops animation
// after killing. Resets counters.
// ----------------------------------------------------------------------------
void CThreadEngine::KillThread(TInt aThreadCount)
{
//Do not kill before threads have been created
if ( iCreatedThreads == EFalse )
{
return;
}
HBufC* killedText;
switch( aThreadCount )
{
case 1:
// Thread can be killed because handle is connected to it.
iThreadOne.Kill(KErrNone);
killedText = StringLoader::LoadLC(R_KILLED_THREAD1);
ThreadKilledText( *killedText, iNotSynchonizedCounter);
CleanupStack::PopAndDestroy(killedText);
iNotSynchonizedCounter = 0;
iView->iAnimationOne->StopAnimation();
break;
case 2:
iThreadTwo.Kill(KErrNone);
killedText = StringLoader::LoadLC(R_KILLED_THREAD2);
ThreadKilledText( *killedText, iSynchronizedCounter);
CleanupStack::PopAndDestroy(killedText);
// Reset counter
SetSyncValue(0);
iView->iAnimationTwo->StopAnimation();
break;
case 3:
iThreadThree.Kill(KErrNone);
killedText = StringLoader::LoadLC(R_KILLED_THREAD3);
ThreadKilledText( *killedText, iSynchronizedCounter );
CleanupStack::PopAndDestroy( killedText );
// Reset counter
SetSyncValue(0);
iView->iAnimationThree->StopAnimation();
break;
}
}
// ----------------------------------------------------------------------------
// CThreadEngine::ExecuteThread(TAny *aPtr)
//
// Threadfunction of threadOne. Executed only by threadOne.
// ----------------------------------------------------------------------------
TInt CThreadEngine::ExecuteThreadOne(TAny *aPtr)
{
// Convert pointer
TInt* notSync = static_cast<TInt*>(aPtr);
TBool loopConditionOne = ETrue;
while ( loopConditionOne )
{
// iNotSynchonizedCounter++, synhronization is not needed because
// only this thread changes iNotSynchronizedCount value.
*notSync = *notSync + 1;
// Wait for a while
User::After( KThreadUpdateInterval );
}
return KErrNone;
}
// ----------------------------------------------------------------------------
// CThreadEngine::ExecuteThreadTwo(TAny *aPtr)
//
// Threadfunction of threadTwo. Executed only by threadTwo.
// ----------------------------------------------------------------------------
TInt CThreadEngine::ExecuteThreadTwo(TAny *aPtr)
{
// Convert pointer
CThreadEngine* engine = static_cast<CThreadEngine*>(aPtr);
TBool loopConditionTwo = ETrue;
while ( loopConditionTwo )
{
// iSynchronizedCounter++;
// The counter is not handled directly, because two threads
// interact with the same variable. Synchronization is needed.
engine->SetSyncValue(engine->GetSyncValue()+1);
User::After( KThreadUpdateInterval );
}
return KErrNone;
}
// ----------------------------------------------------------------------------
// CThreadEngine::ExecuteThreadThree(TAny *aPtr)
//
// Threadfunction of threadThree. Executed only by threadThree.
// ----------------------------------------------------------------------------
TInt CThreadEngine::ExecuteThreadThree(TAny *aPtr)
{
CThreadEngine* engine = static_cast<CThreadEngine*>(aPtr);
TBool loopConditionThree = ETrue;
while ( loopConditionThree )
{
// iSynchronizedCounter++;
// The counter is not handled directly, because two threads
// interact with the same variable. Synchronization is needed.
engine->SetSyncValue(engine->GetSyncValue()+1);
User::After( KThreadUpdateInterval );
}
return KErrNone;
}
// ----------------------------------------------------------------------------
// CThreadEngine::SetSyncValue(TInt aValue)
//
// Set the iSynchronizedCounter value. Synchronization is implemented by using
// a semaphore. Function is thread-safe.
// ----------------------------------------------------------------------------
void CThreadEngine::SetSyncValue(TInt aValue)
{
iMutex.Wait();
iSynchronizedCounter = aValue;
iMutex.Signal();
}
// ----------------------------------------------------------------------------
// CThreadEngine::GetSyncValue() const
//
// Returns iSynchronizedCounter.
//
// ----------------------------------------------------------------------------
TInt CThreadEngine::GetSyncValue() const
{
return iSynchronizedCounter;
}
// ----------------------------------------------------------------------------
// CThreadEngine::CreateThreadsL()
//
// Create three threads and resume them. Start thread animations.
//
// ----------------------------------------------------------------------------
void CThreadEngine::CreateThreadsL()
{
//Create thread1
iThreadOne.Create( _L("thread1") , ExecuteThreadOne, 4096, KMinHeapSize, 256*KMinHeapSize,
&iNotSynchonizedCounter);
iThreadOne.Resume();
iView->iAnimationOne->StartAnimationL();
// Create thread2
// thread two and three modify same counter, that is why a pointer to this class is given,
// not the counter itself. Threads modify iSynchronizedCounter through two CThreadEngine
// functions: GetSyncValue() / SetSyncValue(). Thread2 gets a pointer to CThreadEngine,
// because it must use synchronized funtions to increment the counter.
iThreadTwo.Create( _L("thread2") , ExecuteThreadTwo, 4096, KMinHeapSize, 256*KMinHeapSize,
this);
iThreadTwo.Resume();
iView->iAnimationTwo->StartAnimationL();
//Create thread3
iThreadThree.Create(_L("thread3") , ExecuteThreadThree, 4096, KMinHeapSize, 256*KMinHeapSize,
this );
iThreadThree.Resume();
iView->iAnimationThree->StartAnimationL();
// All threads have been now created. Threads can be killed.
iCreatedThreads = ETrue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -