PostSharp 4.3 / / Post­Sharp Documentation / Threading Patterns / Writing Thread-Safe Code with Threading Models / Opting In and Out From Thread Safety
Opting In and Out From Thread Safety

By default, PostSharp enforces thread safety for all instance fields and all public and internal methods of any class to which you applied a threading model.

However, there are times when you want to opt-out from this mechanism for a specific field or method. A typical reason is that access to the field is synchronized manually using a different mechanism.

This section shows how to override the default thread safety implemented by PostSharp.

This topic contains the following sections:

Opting out from thread-safety verification for a method

To disable enforcement of the class-level threading model for a specific method, add the ExplicitlySynchronizedAttribute attribute to that method.

In the following example, this custom attribute allows us to implement the ToString in a class that respects the Actor model. Without the custom attribute, this would not have been possible because non-void public methods must have the async keyword.

C#
                        [Actor]
                        

                        class
                         Player          
{
   
                        private
                         
                        readonly
                         
                        string
                         name;

   [ExplicitlySynchronized] 
   
                        public
                         
                        override
                         
                        string
                         ToString()
   {
      
                        return
                         
                        this
                        .name;
   }
}
                      

When used on a method, the ExplicitlySynchronizedAttribute attribute has several effects:

  1. Lock-based aspects such as SynchronizedAttribute or ReaderWriterSynchronizedAttribute will not attempt to acquire a lock before executing this method.

  2. Accesses to fields are not verified during the whole execution of the method (for the current thread).

  3. All build-time verifications are disabled for this method.

Caution note Caution

By using the ExplicitlySynchronizedAttribute custom attribute, you are significantly increasing the risk that multithreading defects in user code go undetected by PostSharp. Code using ExplicitlySynchronizedAttribute should be more carefully covered by reviews and tests.

Opting out from thread-safety for a field

To disable enforcement of the class-level threading model for a specific field, add the ExplicitlySynchronizedAttribute attribute to the field:

C#
                        [Actor]
                        

                        class
                         MyActor
{

  [ExplicitlySynchronized]
  
                        int
                         counter;

  
                        public
                         
                        void
                         FooBar()
  {
    
                        // This line would throw an exception without [ExplicitlySynchronized].
                        

                            Task.Factory.StartNew(() => Interlocked.Increment( 
                        ref
                         
                        this
                        .counter ));
  }

}
                      

When used on a field, the ExplicitlySynchronizedAttribute attribute has several effects:

  1. Accesses to the field are never verified

  2. All build-time verifications are disabled for this method.

Opting in for thread safety for callback methods

By default, thread safety is ensured when a thread first invokes a public or internal method of an object. The underlying motivation is that public and internal methods are the primary way how a thread can enter an object. Another way is to enter an object through a delegate call to a private method. By default, PostSharp does not ensure thread safety for private methods. If you register a callback method, you need to add the EntryPointAttribute custom attribute on this method.

In the following code snippet, the OnCreated method is invoked from a background thread by the FileSystemWatcher class. The InputQueueWatcher is thread-safe thanks to the SynchronizedAttribute aspect.

C#
                        [Synchronized]
                        

                        class
                         InputQueueWatcher         
{
  FileSystemWatcher watcher;

  [Child]
  AdvisableCollection<
                        string
                        > files = 
                        new
                         AdvisableCollection<
                        string
                        >();

  
                        public
                         InputQueueWatcher(
                        string
                         path)
  {
    
                        this
                        .watcher = 
                        new
                         FileSystemWatcher();
    
                        this
                        .watcher.Path = path;
    
                        this
                        .watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
    
                        this
                        .watcher.Filter = 
                        "*.xml"
                        ;
    
                        this
                        .watcher.Created += 
                        new
                         FileSystemEventHandler(OnCreated);
  }

  [EntryPoint]
  
                        private
                         
                        void
                         OnCreated(
                        object
                         source, FileSystemEventArgs e)
  {
     
                        // Without [EntryPoint], the following line would throw ThreadAccessException.
                        

                             
                        this
                        .files.Add(e.FullPath);
  }

   
                        public
                         ICollection Files { 
                        get
                         { 
                        return
                         
                        this
                        .files; } }

 }
                      
See Also