diff -r 43e37759235e -r 51a74ef9ed63 Symbian3/SDK/Source/GUID-B7B7F611-BCA0-498F-BEC1-16B276F680D5.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/SDK/Source/GUID-B7B7F611-BCA0-498F-BEC1-16B276F680D5.dita Wed Mar 31 11:11:55 2010 +0100 @@ -0,0 +1,200 @@ + + + + + +Calling +Symbian Asynchronous APIs in Applications +

When porting an P.I.P.S.-based C or C++ application on top of Symbian C++, +the developer may need to make use of Symbian asynchronous APIs. If asynchronous +APIs are made use of in an P.I.P.S. application, the application needs to +wait for the completion of the asynchronous API. This can be done in two ways: +

    +
  • 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. +

+
\ No newline at end of file