Symbian3/SDK/Source/GUID-B7B7F611-BCA0-498F-BEC1-16B276F680D5.dita
author Dominic Pinkman <dominic.pinkman@nokia.com>
Tue, 20 Jul 2010 12:00:49 +0100
changeset 13 48780e181b38
parent 0 89d6a7a84779
permissions -rw-r--r--
Week 28 contribution of SDK documentation content. See release notes for details. Fixes bugs Bug 1897 and Bug 1522.

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-B7B7F611-BCA0-498F-BEC1-16B276F680D5" xml:lang="en"><title>Calling
Symbian Asynchronous APIs in Applications</title><shortdesc/><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>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:
 <ul>
<li><p>Wait for the asynchronous request to complete. This can be achieved
by making use of <codeph>User::WaitForRequest(iStatus)</codeph>; where <codeph>iStatus</codeph> is
the <codeph>TRequestSemaphore</codeph> used by the asynchronous API. </p></li>
<li><p>Call the asynchronous API in an active object, run an active scheduler,
and let the active scheduler wait for the asynchronous operation to complete. </p></li>
</ul></p>
<p><b>The problems with these approaches are: </b></p>
<p>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.</p>
<p>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.</p>
<p>One of the ways to solve these problems is to call the asynchronous APIs
in a separate thread.</p>
<p><b>Example:</b></p>
<codeblock xml:space="preserve">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;
};
</codeblock>
<p>The <codeph>StartThread</codeph> member function of <xref href="GUID-7968C6B4-3247-335A-845B-3D196E2EB14C.dita"><apiname>CActiveThread</apiname></xref> creates
the thread which runs the active scheduler. <codeph>StartMyThread</codeph> 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, <codeph>DoFunction()</codeph> 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 <codeph>RunL()</codeph> based on the <codeph>iState</codeph> and
again goes back to the active scheduler wait loop.  </p>
<p>To synchronize between the parent thread and the child thread, a semaphore
can be used as shown in the following code snippet. </p>
<codeblock xml:space="preserve">CActiveThread* CActiveThread::NewL()
{
CActiveThread* self = new (ELeave) CActiveThread();
self-&gt;ConstructL();
return self;
}
     
CActiveThread::CActiveThread():CActive(EPriorityStandard),iState(EInitialized)
{       
}

void CActiveThread::ConstructL()
{  
// semaphore for Synching
sem_init(&amp;iSem,0,0);  
}
     
void CActiveThread::StartThread()
{       
//Create Thread 
TInt err = iActiveThread.Create( KThreadName(),&amp;CActiveThread::StartMyThread, KDefaultStackSize, NULL, (TAny*)this );
iActiveThread.Logon( iThreadExitWait );
iActiveThread.Resume();
sem_wait(&amp;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-&gt;iWait = new (ELeave) CActiveSchedulerWait();	    
thisptr-&gt;iState = EInitialized;
thisptr-&gt;iStatus = KRequestPending;
thisptr-&gt;SetActive();
sem_post( &amp;(thisptr-&gt;iSem ));    
thisptr-&gt;iWait-&gt;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-&gt;AsyncStop();    
     return;			
     }
	
iStatus = KRequestPending;
SetActive();
// wake up the waiting thread
sem_post(&amp;iSem);
}

void CActiveThread::DoCancel()
{    
}

void CActiveThread::DoFunction(TState aState )
{
iState = aState;
TRequestStatus *reqPtr = &amp;iStatus;
iActiveThread.RequestComplete( reqPtr, KErrNone );
sem_wait(&amp;iSem);
}    
 
CActiveThread::~CActiveThread()
{  
if ( iState != EInitialized )
    {
    iState = ECompleted;
    TRequestStatus *reqPtr = &amp;iStatus;	
    iActiveThread.RequestComplete( reqPtr, KErrNone ); 
    User::WaitForRequest( iThreadExitWait);
    }    
sem_destroy(&amp;iSem);
}
</codeblock>
<p><b>Using <xref href="GUID-7968C6B4-3247-335A-845B-3D196E2EB14C.dita"><apiname>CActiveThread</apiname></xref>:</b></p>
<codeblock xml:space="preserve">iMyAsyncIf = CActiveThread::NewL();   
iMyAsyncIf-&gt;StartThread();    
iMyAsyncIf-&gt;DoFunction(EDoFirst);
</codeblock>
<p><b>Limitations: </b></p>
<p>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.
 </p>
</conbody></concept>