| Severity | Error |
| Reported by | PostSharp.Patterns.Threading |
| Message | Cannot apply [Reentrant] to "<Method>" because the method is not async. |
Cause
The ReentrantAttribute attribute means that an async method can be re-entered at each await: with a lock-based threading model such as SynchronizedAttribute, the lock of the object is released while the method awaits; with ActorAttribute, other methods of the actor can run in the meantime. A method that is not async has no await at which this could happen.
PostSharp reports THR022 when the attribute is applied to a method that is not async, including a method that returns a Task without the async keyword. PostSharp does not check a method that also has the ExplicitlySynchronizedAttribute attribute.
In the following example, the ArchiveAsync method returns a Task, but it is not async.
using System;
using System.Threading.Tasks;
using PostSharp.Patterns.Threading;
namespace Errors.THR022_Error;
[Synchronized]
public class OrderArchive
{
private int archivedCount;
public int ArchivedCount => this.archivedCount;
// The method returns a Task, but it is not async.
[Reentrant]
public Task ArchiveAsync( string order )
{
this.archivedCount++;
return Task.Delay( 10 );
}
}
public static class Program
{
public static void Main()
{
var archive = new OrderArchive();
archive.ArchiveAsync( "Order 1" ).Wait();
archive.ArchiveAsync( "Order 2" ).Wait();
Console.WriteLine( $"Archived orders: {archive.ArchivedCount}" );
}
}
error THR022: THR022_Error.cs(16,17): Cannot apply [Reentrant] to "Errors.THR022_Error.OrderArchive.ArchiveAsync(System.String)" because the method is not async.
Resolution
- When the method awaits a task, make it
asyncandawaitthe task, so that the object can be re-entered while it waits. - Otherwise, remove the
[Reentrant]attribute: a method that is notasyncdoes not need it.
In the following example, the ArchiveAsync method is async.
using System;
using System.Threading.Tasks;
using PostSharp.Patterns.Threading;
namespace Errors.THR022_Fixed;
[Synchronized]
public class OrderArchive
{
private int archivedCount;
public int ArchivedCount => this.archivedCount;
// The method is async, so the lock of the object is released while it awaits.
[Reentrant]
public async Task ArchiveAsync( string order )
{
await Task.Delay( 10 );
this.archivedCount++;
}
}
public static class Program
{
public static void Main()
{
var archive = new OrderArchive();
archive.ArchiveAsync( "Order 1" ).Wait();
archive.ArchiveAsync( "Order 2" ).Wait();
Console.WriteLine( $"Archived orders: {archive.ArchivedCount}" );
}
}
Archived orders: 2
See Also
Reference
ReentrantAttribute
SynchronizedAttribute
ActorAttribute
Other Resources