Notes on using RTPointer |
Category: |
C++
Purpose: |
To clarify RTPointer usage
Intended Audience: |
ObjecTime Developer users
Applicable to: |
All Versions
Description: |
A common design mistake is to treat RTPointer as a pointer.
RTPointer is a class, not a pointer or an address. It is a subclass of RTByteBlock.
For a definition of RTPointer see:
Because RTPointer is a class, the following two constructs are invalid:
RTPointer ptrWrapper = &someData; //Wrong RTPointer ptrWrapper = (RTPointer)&someData //Wrong* //This is the old c-struct cast form. It is bad form //and may not work with all compilers. See below for //the correct, less ambiguous form.
An instance of the RTPointer class is an object which provides a wrapper around the address of some data. The RTPointer constructor takes a pointer as an arguement.
The correct usage of RTPointer is:
RTPointer ptrWrapper = RTPointer(&someData);//Correct
There is a POINTER_OF(type) macro, (the definition is missing from the current documentation set). It looks like:
#define POINTER_OF( type ) (type *)(void *)*(RTPointer *)
The ObjecTime recommended technique for retrieving a pointer from an RTPointer is:
MyData* myDataPtr = POINTER_OF(ptrWrapper);//Correct
This is equivalent to, but less error prone than, using the RTPointer void* interface:
MyData* myDataPtr = (MyData *) (void *) ptrWraper;
ObjecTime recommends that you do not take advantage of the RTPointer instance variable "Contents" which holds the pointer. For example, although the following construct will work:
MyData* myDataPtr = (MyData *) ptrWrapper.Contents;
"Contents" is not part of the published interface and could change in a future ObjecTime release.
When sending an RTPointer object in a message, ObjecTime recommends that you use the provided SEND_PTR and RECEIVE_PTR macros (see pg. 26 of the ObjecTime4.3 C++ User Guide, or pg. 278 of the ObjecTime5.0 C++ User Guide).
By using these macros you will ensure compatability between the SimulationRTS and the TargetRTS and thereby avoid transition problems.
Here is an example of using the SEND_PTR macro:
MyStruct *myPtr = ...;
outPort.send( aSignal, SEND_PTR( myPtr ) );
and here is an example of using the RECEIVE_PTR macro:
MyStruct *strptr = RECEIVE_PTR( MyStruct );
Sending pointers to functions is also relatively straightforward. Given a global function:
int myFnc(char*);
to send a function pointer using RTPointer, use:
aPort.send(aSignal, SEND_PTR((void *) &myFnc) );
On the receiving side, to access the function, use:
int (*foo) (char *) = (int (*) (char *)) RECEIVE_PTR(void);
The function could then be called with:
(*foo)(&aCharacter);
This techique will not work for member functions which need to access member data.For an example of sending member function pointers, see page 186-187 of the ObjecTime5.0 C++ guide.
Care must be exercised when sending function pointers. Both the sender and the receiver must share the same address space. When sending function pointers across thread boundaries, like with access to global data, static member data, etc., you may need mechanisms to safely protect shared memory.
Actor transitions have run-to-completion semantics. Local variables will go out of scope at transition completion. If you send a pointer of a local variable, it will be out of scope by the time the receiver gets it (i.e., the pointer will be invalid!). There are two possible exceptions to this rule:
Keep in mind that by taking advantage of either of these exceptions your application will be less robust. It will likely be broken by future application modifications or ObjecTime releases.
Sending a pointer of a locally scoped variable is never recommended.
When using sharing memory (i.e., sending pointers) extra attention is required to avoid introducing difficult to track bugs. Here are some things to consider:
In practice it is safer to only send pointers to: extended state variables; global data; or memory allocated off the heap. Be aware that by sending pointers you are coupling the implementation of one part of the system to another part of the system. This coupling, is architecturally significant, but will not be visible in the structure of your system. It is a likely source of bugs and is potentially the beginning of architectural "erosion".
Consider other strategies for optimizing performance such as reallocating actor responsibilities so that only one actor requires the data.
Limitations: |
None
See also: |
ObjecTime C++ guide
Copyright © 1999, ObjecTime Limited. |