MSDN Magazine - December 2007 - (Page 23) To give your code an opportunity to execute, the CLR will eagerly prepare your code, meaning it will JIT the statically discoverable call graph for your method. If you use delegates within a CER, the target method of the delegate must be eagerly prepared, preferably by calling RuntimeHelpers.PrepareMethod() on the method. Additionally, if you use ngen, you can mark the method with the PrePrepareMethodAttribute to eliminate some need to pull in the JIT. This eager preparation will eliminate CLR-induced out-of-memory exceptions. With regard to thread aborts, the CLR will disable these over CERs. The CLR will also probe for some stack, if and only if the CLR’s host (for example, any native app that uses the CLR’s COM hosting interfaces to launch the CLR) wants to survive stack overflow. Barring bugs in the runtime itself, heap corruption, and hardware problems, this should eliminate all CLR-induced asynchronous exceptions caused by your code. Figure 1 A Stronger Consistency Guarantee [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void InsertItem (ReliableList list, T item) { RuntimeHelpers.PrepareConstrainedRegions(); // CER marker try { // Add can fail with an OutOfMemoryException. // That’s fine, since the list didn’t change. list.Add(item); // Consider a failure here, perhaps from calling a second method. } finally { // Restore consistency by guaranteeing the list is sorted. list.Sort(); } } Reliability Contracts You may have noticed that I keep drawing a line between CLRinduced failures and all other failures. Failures can occur at all levels of the system since each layer of the system has a different view of consistency. Consider an application that wants to maintain a list of items in sorted order. If you use an unsorted collection like List , your code may look like this: public static void InsertItem (List list, T item) { // List isn’t sorted, but the app relies on it being sorted. list.Add(item); list.Sort(); } whether to expect the possibility of a failure. Here, reliability contracts could do a better job of indicating corruption of parameters versus a “this” pointer, but these are really meant to start a reliability discussion between the author of the InsertItem method and the person calling it. In this case, someone calling InsertItem will notice that it may cause corruption of an instance if it fails, so they will know that they need a mitigation strategy. Mitigating Failures the Hard Way Constrained execution regions offer some ways to mitigate failures in code like InsertItem. The options vary in complexity and some techniques may not work well if the code changes significantly from one version to another. The most obvious technique is to try to understand the failure and avoid it. In this sample, it may be possible to hoist allocations to a place where you can recover from the failure, such as allocating the list with sufficient capacity to begin with. This would hoist any allocation failures. However, this requires that you understand InsertItem , List , and how they both fail. Additionally, this technique doesn’t solve the thread abort problem. The list may still not be sorted. Here, a CER could be used to ensure that the finally block is sorted all the time. Regardless of whether Add fails or not, we ensure consistency of the list by guaranteeing that it is sorted. This requires a strong reliability guarantee on our fictitious ReliableList ’s Sort method. But with that in place, we could write our code as shown in Figure 1, offering a stronger consistency guarantee in InsertItem’s reliability contract. Keep in mind that these techniques don’t work in a real-world implementation of this example since ReliableList doesn’t really exist. It would be particularly difficult to write due to the nature of sort algorithms—you need any comparer used by Sort and most likely T’s CompareTo method to also be reliable. But there’s another technique similar to the recycling model. If you can live with the performance hit, you can copy the data, make your changes on your copy, and then expose your consistent data structure to the world. Here’s one way to do this, complete with compromises to the method signature: [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void InsertItem (ref List list, T item) Now imagine that all the methods on List magically succeeded all the time. We’ll use the hypothetical ReliableList to imply this behavior. Imagine that Add never needs to grow the size of the list and the Sort routine always works (even with its indirect calls into comparers and CompareTo methods on the generic type T). If a ThreadAbortException occurs in InsertItem after the call to Add completed but before the call to Sort, we still run into a consistency problem. From the perspective of ReliableList , the list is fully consistent. The internal data structures in the list are in a perfectly fine state in that there is no extra item half-added to the collection. And we can continue to use the list without any problems. But, from the perspective of the application (remember that it required the list to be sorted), this invariant has been broken and the method hasn’t been written to recover from this problem. This scenario illustrates that consistency exists at various levels in the system. This is indicated to users via reliability contracts—a very coarse-grained mechanism for stating the extent of corruption if an asynchronous exception occurs. In this case, the method corrupted the list, and if we admit the possibility of an OutOfMemoryException during the Add method call, then we have to mark this method as potentially failing, like this: [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] public static void InsertItem (ReliableList list, T item) Reliability contracts, which are required on all code called within CERs, serve primarily as documentation to the developer about CLR Inside Out december2007 23
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.