By default, objects are copied from one application area to another (passed by value). The Remote Access section shows how to link between application areas. This ensures that the code of one application area is isolated from the code of another.
Objects are passed by reference between contexts. This allows the clR runtime common language to meet the requirements (such as synchronization or transactions) of different objects, regardless of whether the client of the object is in the same application area or in a different one.
Because most objects do not derive from a ContextBoundObject, they can be persistently stored in one context or moved from one context to another as needed. However, threads can cross application area or context boundaries within the same Win32 process.
.NET supports a design pattern for asynchronous programming. This pattern is used in many places in .NET (including I/O, as noted earlier, and as will be discussed in more detail in Chapter 11, "Web Services"). Asynchronous programming can call a method without blocking the calling program method. From the client's perspective, using the asynchronous model is easier than threads. However, it provides much less control over synchronization compared to using sync objects. Therefore, class developers will probably find it much easier to use threads.
Asynchronous design patterns
This design pattern consists of two parts: a set of methods and the lAsyncResult interface. The template methods are as follows:
lAsyncResult *BeginXXX( [InputParams], AsyncCallback *cb, Object *AsyncObject) [ReturnValue] EndXXX([OutputParams], lAsyncResult *ar);
In the design pattern, XXX denotes a real method that is called asynchronously (for example, BeginRead/EndRead for the System::IO::FileStream class). BeginXXX must accept the same input parameters as its synchronous counterpart (in, in/out, and ref), as well as the AsyncCallback and AsyncObject parameters. The EndXXX signature must contain all output parameters (ref, out, in/out) of the synchronous version. This method should return any object or value that the synchronous version of this method returns. It must also have the lAsyncResult parameter. The Cancelx method can also be provided if it is needed.
AsyncCallback is a delegate that represents the callback function.
public _delegate void AsyncCallback(lAsyncResult *ar);
AsyncObject is available from lAsyncResult. This is implemented so that in the callback function, you can determine during which asynchronous read the callback was made.
The wireframe uses this pattern so that the synchronous Read method of the FileStream class can be used asynchronously. The following is a description of the synchronous FileStream::Read method:
int Read(// Read
_in unsigned char* array _gc,
int offset, int count);
// int offset, int counter);
And here's the asynchronous version used in the design pattern:
_in unsigned char* array _gc,
int offset, int numBytes,
Object *stateObject); // An object
int EndRead(lAsyncResult *asyncResult);
Any exception that is thrown in BeginXXX must be run before asynchronous operations can be performed. Each exception associated with asynchronous operations must be thrown from the EndXXX method.
The BeginXXX method (such as BeginRead) returns lAsyncResult. The following interface contains four elements:
// garbage collector - interface lAsyncResult
bool get_IsCompleted(); // logical (boolean)
bool get_CompletedSynchronously();// boolean
Object* get_AsyncState(); }
The get_IsCompleted field will be set to true after the call is processed by the server. The client can destroy all resources after the get_IsCompleted is set to true. The get_CompletedSynchronously field will be set to true if BeginXXX ends synchronously. Most often, this field is ignored and by default its value is set to false. Typically, the client does not even know whether the BeginXXX method is executed synchronously or asynchronously. If the asynchronous operation is not complete, the EndXXX method is blocked until the operation completes.
The get_AsyncWaitHandle method returns a WaitHandle that can be used for synchronization purposes. We have previously seen that this handle is capable of receiving signals so that the client can arrange a wait with it. Because you can specify a time-out period, you do not need to be permanently blocked if the operation is not yet complete.
The get_AsyncState object is the last parameter in the call to the BeginXXX method. It allows you to differentiate read processes asynchronously during a callback.