Symbian OS Explained - Effective C++ Programming For Smartphones (2005) (779885), страница 41
Текст из файла (страница 41)
The server usesnon-pre-emptive active-object event-handling (described in Chapters 8and 9). The response time is determined by the longest possible RunL()event-handler method of any active object running on the server thread,because an active object cannot be pre-empted when it is handlingan event.If a client makes a request while the server thread is already handlingan event in a RunL() method, it runs to completion before the clientrequest can be serviced. This is also true for external events occurringfrom resources owned by the server. Thus, if you want to write a highperformance server, there should be no long-running RunL() methodsin any active objects in the server’s main thread.This includes processing in the ServiceL() method of theCSharableSession-derivedclass,whichiscalledbyCServer::RunL().
This means that long-running operations must beperformed by a separate thread or server.Furthermore, the priority of a server thread should be chosen accordingto the maximum guaranteed response time, that is, the longest RunL()method of the server.
You should not give a high priority to a serverthread that performs lots of processing in its event handler, since it mayblock threads with more appropriately chosen, lower, priorities.11.13What Are the Advantages of a Local (Same-Process)Server?Local servers are useful when several related servers can run in thesame process. For example, Symbian OS v7.0 runs the serial communications server, sockets server and telephony server in the same process(C32.exe). The servers are in a different process to their clients, so acontext switch is still required, and resource integrity is maintained bythe separation.
However, interactions between the three servers occur inthe same process and have a correspondingly lower overhead than theywould otherwise (I’ll describe the overheads associated with using theclient–server model in more detail shortly).A private local server runs in the same process as its clients.
It canbe useful, for example, if you need to share client sessions to a serverwhich does not support sharable sessions. The client process should use aprivate local server which does support sharable sessions and has a singleopen session with the non-sharable server. This private server servicesWHAT ARE THE OVERHEADS OF CLIENT–SERVER COMMUNICATION?183requests from each of the client threads, passing them through as requeststo its single session with the non-sharable server.11.14What Are the Overheads of Client–ServerCommunication?Session OverheadAlthough a client can have multiple sessions with a server, each sessionconsumes limited resources in both the server and the kernel. For eachopen client session, the kernel creates and stores a DSession objectand the server creates an object of a CSharableSession-derived class.This means that each connecting session may give rise to a significantspeed overhead.
Rather than creating and opening multiple sessions ondemand, client code should aim to minimize the number of sessions used.This may involve sharing a session, or, for servers which do not supportthis, passing the open session between functions or defining classes thatstore and reuse a single open session.For efficiency, where multiple sessions are required, a client–serverimplementation may provide a subsession class to reduce the expense ofmultiple open sessions.
To use a subsession, a client must open a sessionwith the server as normal, and this can then be used to create subsessionswhich consume fewer resources and can be created more quickly. Thisis done using the RSubSessionBase class, the definition of which isshown below (from e32std.h):class RSubSessionBase{public:inline TInt SubSessionHandle();protected:inline RSubSessionBase();inline RSessionBase& Session();IMPORT_C TInt CreateSubSession(RSessionBase& aSession,TInt aFunction,const TAny* aPtr);IMPORT_C void CloseSubSession(TInt aFunction);IMPORT_C TInt Send(TInt aFunction,const TAny* aPtr) const;IMPORT_C void SendReceive(TInt aFunction,const TAny* aPtr,TRequestStatus& aStatus) const;IMPORT_C TInt SendReceive(TInt aFunction,const TAny* aPtr) const;private:RSessionBase iSession;TInt iSubSessionHandle;};A typical client subsession implementation derives from RSubSessionBase in a similar manner to a client session, which derivesfrom RSessionBase. The deriving class provides simple wrapper functions to hide the details of the subsession.
To open a subsession, the184THE CLIENT–SERVER FRAMEWORK IN THEORYderived class should provide an appropriate wrapper function (e.g.Open()) which calls RSubSessionBase::CreateSubSession(),passing in an existing RSessionBase-derived session object. CreateSubSession() also takes an integer ”opcode” to identify the ”createsubsession” request, and a pointer to an array of pointers (which may beused to pass any parameters required to service the request across theclient–server boundary).Once the subsession has been created, RSubSessionBase::SendReceive() and Send() methods can be called, by analogy with thosein RSessionBase, but only three parameters of the request data arraymay be used because the subsession class uses the last element of thedata array to identify the subsession to the server.On the server side, the code to manage client–server subsessionscan be quite complex. It usually requires reference counting to manage subsessions over the lifetime of the session, and typically uses theCObject-derived classes.
You can find more information about these,somewhat confusing, classes in your SDK documentation.A good example of the use of subsessions is RFile, which derivesfrom RSubSessionBase and is a subsession of an RFs client sessionto the file server. An RFile object represents a subsession for accessto individual files. I’ll illustrate the use of RFs and RFile later in thischapter, but you should consult your SDK for further information aboutthe use of the Symbian OS filesystem APIs.It’s worth noting that connections to the file server can take a significantamount of time to set up (up to 75 ms). Rather than creating multiplesessions on demand, RFs sessions should be passed between functionswhere possible, or stored and reused.Each client–server session has an associated overhead in the kerneland server.
Client code should minimize the number of sessionsit uses, for example by sharing a session, or by defining classesthat store and reuse a single open session. A server may alsoimplement subsessions to be used as lightweight alternatives tomultiple open sessions.Performance OverheadYou should be aware of the system performance implications when usingthe client–server model. The amount of data transferred between theclient and server does not cause so much of an overhead as the frequencywith which the communication occurs.The main overhead arises because a thread context switch is necessaryto pass a message from the client thread to the server thread and backWHAT ARE THE OVERHEADS OF CLIENT–SERVER COMMUNICATION?185again.
If, in addition, the client and server threads are running in differentprocesses, a process context switch is also involved.A context switch between threads stores the state of the running thread,overwriting it with the previous state of the replacing thread. If the clientand server threads are in the same process, the thread context switchstores the processor registers for the threads. If the client and server arerunning in two separate processes, in addition to the thread context,the process context (the address space accessible to the thread), mustbe stored and restored. The MMU must remap the memory chunks foreach process, and on some hardware this means that the cache must beflushed. The exact nature of the overhead of a thread or process contextswitch depends on the hardware in question.Inter-thread data transfer between threads running in separate processes can also have an overhead because an area of data belonging tothe client must be mapped into the server’s address space.How Can I Improve Performance?For performance reasons, when transferring data between the client andserver, it is preferable, where possible, to transfer a large amount of datain a single transaction rather than to perform a number of server accesses.However, this must still be balanced against the memory cost associatedwith storing and managing large blocks of request data.For example, Symbian OS components that frequently transfer datato or from the filesystem generally do not use direct filesystem accessmethods such as RFile::Read() or RFile::Write().