Wait for the asynchronous request to complete. This can be achieved
by making use of User::WaitForRequest(iStatus)
; where iStatus
is
the TRequestSemaphore
used by the asynchronous API.
Call the asynchronous API in an active object, run an active scheduler, and let the active scheduler wait for the asynchronous operation to complete.
The problems with these approaches are:
The open source application would get blocked till the asynchronous operation completes in the first approach. In the second approach, the active scheduler would be running in a wait loop, checking for asynchronous API completion. Even in this case, the P.I.P.S. application would not be able to perform any other operations outside the active scheduler framework.
The asynchronous APIs could be called in a separate process, and the P.I.P.S. application could communicate with this process by making use of the client/server framework of Symbian or by making use of other P.I.P.S. IPC mechanisms. However, making a different process for calling asynchronous APIs might pose a performance hit.
One of the ways to solve these problems is to call the asynchronous APIs in a separate thread.
Example:
class CActiveThread: public CActive { public: enum TState { EInitialized = 0x0, EDoFirst = 0x1, EDoSecond = 0x2, EDoThird = 0x4, ECompleted = 0x8 }; // thread startup routine static int StartMyThread(void* thisptr); // leaving variant of the thread startup routine static int StartMyThreadL(void* thisptr); // Helper function to start the thread void StartThread(); // Do Function void DoFunction(TState aState ); // CActive Functions void RunL(); void DoCancel(); // Constructors and destructor static CActiveThread* NewL(); CActiveThread (); void ConstructL(); ~ CActiveThread(); private: // Active Scheduler CActiveSchedulerWait *iWait; // Command/State TInt iState; TRequestStatus iThreadExitWait; // my thread handle RThread iActiveThread; sem_t iSem; };
The StartThread
member function of CActiveThread creates
the thread which runs the active scheduler. StartMyThread
is
the entry point function for the new thread that starts an active scheduler
and sets up the clean up stack. To call an asynchronous function, DoFunction()
needs
to be called with the corresponding state. The parent thread signals the child
thread using the child thread’s thread request semaphore. When the thread
request semaphore is signaled, the child thread wakes up, calls the corresponding
asynchronous API in RunL()
based on the iState
and
again goes back to the active scheduler wait loop.
To synchronize between the parent thread and the child thread, a semaphore can be used as shown in the following code snippet.
CActiveThread* CActiveThread::NewL() { CActiveThread* self = new (ELeave) CActiveThread(); self->ConstructL(); return self; } CActiveThread::CActiveThread():CActive(EPriorityStandard),iState(EInitialized) { } void CActiveThread::ConstructL() { // semaphore for Synching sem_init(&iSem,0,0); } void CActiveThread::StartThread() { //Create Thread TInt err = iActiveThread.Create( KThreadName(),&CActiveThread::StartMyThread, KDefaultStackSize, NULL, (TAny*)this ); iActiveThread.Logon( iThreadExitWait ); iActiveThread.Resume(); sem_wait(&iSem ); } int CActiveThread::StartMyThread( void* ptr ) { CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); CActiveScheduler::Install(scheduler); CTrapCleanup* pCleanup = CTrapCleanup::New(); TRAPD(err, StartMyThreadL(ptr)); } int CActiveThread::StartMyThreadL( void* ptr ) { CActiveThread *thisptr = (CActiveThread*)ptr; CActiveScheduler::Add(thisptr); thisptr->iWait = new (ELeave) CActiveSchedulerWait(); thisptr->iState = EInitialized; thisptr->iStatus = KRequestPending; thisptr->SetActive(); sem_post( &(thisptr->iSem )); thisptr->iWait->Start(); } void CActiveThread::RunL() { switch ( iState ) { case EDoFirst: // Call 1st asynchronous function break; case EDoSecond: // Call 2nd asynchronous function break; case EDoThird: // Call 3rd asynchronous function break; case ECompleted: iWait->AsyncStop(); return; } iStatus = KRequestPending; SetActive(); // wake up the waiting thread sem_post(&iSem); } void CActiveThread::DoCancel() { } void CActiveThread::DoFunction(TState aState ) { iState = aState; TRequestStatus *reqPtr = &iStatus; iActiveThread.RequestComplete( reqPtr, KErrNone ); sem_wait(&iSem); } CActiveThread::~CActiveThread() { if ( iState != EInitialized ) { iState = ECompleted; TRequestStatus *reqPtr = &iStatus; iActiveThread.RequestComplete( reqPtr, KErrNone ); User::WaitForRequest( iThreadExitWait); } sem_destroy(&iSem); }
Using CActiveThread:
iMyAsyncIf = CActiveThread::NewL(); iMyAsyncIf->StartThread(); iMyAsyncIf->DoFunction(EDoFirst);
Limitations:
In this approach, only the parent thread communicates with the child thread. There is no way for the child thread to communicate with the parent thread.