Writing Thread-Safe Code with Threading Models
A threading model is a design pattern that gives guarantees that your code executes safely on a multithreaded computer. Threading models both define coding rules (for instance: all fields must be private) and add new behaviors to existing code (for instance: acquiring a lock before method execution). Coding rules are typically enforced at build time or at run time; violations result in build-time errors or run-time exceptions. Threading models may also require the use of custom attributes in source code, for instance to indicate that a method requires read access to the object.
We recommend assigning a threading model to every class whose instances can be shared between different threads.
Threading models raise the level of abstraction at which multi threading is addressed. Compared to working directly with locks and other low-level threading primitives, using threading models has the following benefits:
Threading models are named solutions to a recurring problem. Threading models are specific types of design patterns, and have the same benefits. When team members discuss the multithreaded behavior of a class, they just need to know which threading model this class uses. They don't need to know the very details of its implementation. Since the human short-term memory seems to be limited to 5-9 elements, it is important to think in terms of larger conceptual blocks whenever we can.
Much of the code required to implement the threading model can be automatically generated, which decreases the number of lines of code, and therefore the number of defects. It also reduces development and maintenance costs.
Your source code can be automatically verified against the selected threading model, both at build time and at run time. This makes the discovery of defect much more deterministic. Without verifications, threading defects usually show up randomly and provoke data structure corruption instead of immediate exceptions. Run-time verification would be too labor-intensive to implement without compiler support, so would be most likely omitted.
Available threading models
PostSharp Threading Library provides an implementation for the following threading models:
|Threading Model||Aspect Type||Description|
|Thread-Unsafe Threading Model||ThreadUnsafeAttribute||These objects may never be accessed concurrently by several threads.|
|Thread Affine Threading Model||ThreadAffineAttribute||These objects must be accessed from the thread that instantiated them.|
|Synchronized Threading Model||SynchronizedAttribute||Synchronized objects can be accessed by a single thread at a time. Other threads will wait until the object is available.|
|Reader/Writer Synchronized Threading Model||ReaderWriterSynchronizedAttribute||These objects that can be read concurrently by several threads, but write access requires exclusivity. Public methods of this object must specify which kind of access they require (read or write, typically).|
|Actor Threading Model||ActorAttribute||These objects communicate with their clients using an asynchronous communication pattern. All accesses to the object are queued and then processed in a single thread. However, queuing is transparent to clients, which just call standard
|Freezable Threading Model||FreezableAttribute||These objects can be set to a state where their property values can no longer be changed. Unlike immutable objects, the developer dictates the time and place in their code where changes to the object's state will no longer be accepted.|
|Immutable Threading Model||ImmutableAttribute||These objects cannot have their state changed after their constructor has finished executing.|
|Making a Whole Project or Solution Thread Safe||This article describes how to get compiler warnings when you forget to assign a threading model to a type.|
|Opting In and Out From Thread Safety||This article shows how to disable the enforcement of the threading model for specific fields or methods.|
|Compatibility of Threading Models||This article lists compatibility of threading models when they are applied to objects that are in a parent-child relationship.|
|Enabling and Disabling Runtime Verification||This article explains when runtime verification is enabled or disabled and how to customize the default behavior.|
Please read this technical white paper for details about the concepts and architecture of PostSharp Threading Models.