How can I prevent an async method from being reentrant? - c#

I have an async method in my program. I need the task to be asynchronous because it makes network requests, but I don't want it to be reentrant. In other words, if the method is called from code block A, and then again from code block B before the first invocation returns, I want the second invocation to wait until the first invocation finishes before it runs.
If the method were not an async method, I'd be able to accomplish it with this annotation:
[MethodImpl(MethodImplOptions.Synchronized)]
However, the compiler does not allow the annotation to be attached to an async method.
What else can I do?

You can use a SemaphoreSlim, which is a lock with a WaitAsync method on it (and which doesn't mind you releasing it on a different thread to the one you acquired it on).
private readonly SemaphoreSlim methodLock = new SemaphoreSlim(1, 1);
public async Task SomeMethod()
{
await methodLock.WaitAsync();
try
{
...
}
finally
{
methodLock.Release();
}
}
If you're feeling adventurous, you can write an extension method on SemaphoreSlim, letting you do e.g.:
public async Task SomeMethod()
{
using (await methodLock.WaitDisposableAsync())
{
...
}
}
Be careful though: SemaphoreSlim is not recursive (nor can it be). That means if your method is recursive, it will deadlock.

Related

SemaphoreSlim - is it ok to use it in multiple methods to wait and release?

I have an Asp.Net Core 6 Web Api.
I have a Singleton class with several methods in it.
I want only 1 thread to enter any of the methods of the class at a time.
Is it ok to initialize the SemaphoreSlim class in the constructor and use it in every method in the following way? Are there any dangers from it?
Is there a better way to achieve what I am looking for?
public class Foo
{
private readonly SemaphoreSlim _sm;
public Foo()
{
_sm = new SemaphoreSlim(1, 1);
}
public async Task FirstMethod()
{
await _sm.WaitAsync();
//Do some work
_sm.Release();
}
public async Task SecondMethod()
{
await _sm.WaitAsync();
//Do some work
_sm.Release();
}
}
You should adopt the try/catch/finalize pattern - if you do so, you're mostly safe: all code under the WaitAsync will be executed as defined by the max semaphore. Only if the code under the semaphore block, you'll get a deadlock - you could consider using a timeout, but typically this is accepted.
public async Task SecondMethod()
{
await _sm.WaitAsync();
try
{
//Do some work
}
finally
{
//release in case of errors
_sm.Release();
}
}
Other stuff to consider is, especially if it is a long running process, is to use a cancellation token to indicate application closure.
Also keep in mind that if you fire a lot of these methods from various threads, the order is not guaranteed - but they will all be handled.

Is there any way to know if a method is running being awaited from within the method?

I'm a university student but, since I like programming, I try to create a library of code that's been useful to me (something like a code base).
In the process of doing this, I started designing/writing an asynchronous method that's about to be used for interlocking a variable. My goal is to produce different result when this method is being awaited (runs synchronously) and when it isn't.
An example could be the following:
private int _lock;
public async Task<bool> Lock()
{
if (method_is_not_being_awaited)
return Interlocked.Exchange(ref _lock, 1) == 0;
while (0 != Interlocked.Exchange(ref _lock, 1)) {}
return true;
}
Is there any way to achieve such result? If yes, how?
ps: I know that I could make 2 different methods bool lock() and async Task<bool> lockAsync() but, that's not what I ask for
No, it is not possible to do what you want because method must return value before any operation on result (including await) can be performed. It is not specific to async methods but rather how all code behaves in C# (and pretty much any other language).
On other hand it is pretty easy to do something that very close to what you ask - synchronously return value as soon as one tries to await the result of the method: await is essentially just call to GetAwaiter on the result and you can wire it up to alter state of your method.
Note that you can't really know what to do if method ever awaited anyway - so while you can act at moment when await is called you really can't know in advance if you should start asynchronous processing. So the best you can achieve is to do nothing in synchronous part, start asynchronous processing anyway and instantly return result when await is called (aborting/ignoring asynchronous part of the method).
Details on implementing class that can be used as result can be found in https://www.codeproject.com/Articles/5274659/How-to-Use-the-Csharp-Await-Keyword-On-Anything and https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model.
Skeleton code below shows how to implement method that does nothing unless await is called:
class MyTask
{
public MyAwaitable GetAwaiter()
{
return new MyAwaitable();
}
}
class MyAwaitable : INotifyCompletion
{
public bool IsCompleted
{
get { return true; }
}
public int GetResult()
{
return 42; // this is our "result" from method.
}
public void OnCompleted (Action continuation)
{
// just run instantly - no need to save callback as this one is
// always "completed"
continuation();
}
}
MyTask F()
{
// if your really want you can start async operation here
// and somehow wire up MyAwaitable.IsComplete to terminate/abandon
// asynchronous part.
return new MyTask();
}

System.Threading.Channels ReadAsync() method is blocking execution

Overview
I am attempting to write an IAsyncEnumerable<T> wrapper around an IObserver<T> interface. At first I used a BufferBlock<T> as the backing data store, but I found out through performance testing and research that it is actually a pretty slow type, so I decided to give the System.Threading.Channels.Channel type a go. I had a similar problem with my BufferBlock implementation as this one but this time I'm not sure how to resolve it.
Problem
My GetAsyncEnumerator() loop gets blocked by the await _channel.Reader.WaitToRead(token) call if my IObserver<T>.OnNext() method hasn't written to the _channel yet. What is the correct way to wait for a value to be available to yield in this context without blocking program execution?
Implementation
public sealed class ObserverAsyncEnumerableWrapper<T> : IAsyncEnumerable<T>,
IObserver<T>, IDisposable
{
private readonly IDisposable _unsubscriber;
private readonly Channel<T> _channel = Channel.CreateUnbounded<T>();
private bool _producerComplete;
public ObserverAsyncEnumerableWrapper(IObservable<T> provider)
{
_unsubscriber = provider.Subscribe(this);
}
public async void OnNext(T value)
{
Log.Logger.Verbose("Adding value to Channel.");
await _channel.Writer.WriteAsync(value);
}
public void OnError(Exception error)
{
_channel.Writer.Complete(error);
}
public void OnCompleted()
{
_producerComplete = true;
}
public async IAsyncEnumerator<T> GetAsyncEnumerator(
[EnumeratorCancellation] CancellationToken token = new CancellationToken())
{
Log.Logger.Verbose("Starting async iteration...");
while (await _channel.Reader.WaitToReadAsync(token) || !_producerComplete)
{
Log.Logger.Verbose("Reading...");
while (_channel.Reader.TryRead(out var item))
{
Log.Logger.Verbose("Yielding item.");
yield return item;
}
Log.Logger.Verbose("Awaiting more items.");
}
Log.Logger.Verbose("Iteration Complete.");
_channel.Writer.Complete();
}
public void Dispose()
{
_channel.Writer.Complete();
_unsubscriber?.Dispose();
}
}
Additional Context
It shouldn't matter, but at runtime the IObservable<T> instance passed into the constructor is a CimAsyncResult returned from async calls made to the Microsoft.Management.Infrastructure apis. Those make use of the Observer design pattern which I'm trying to wrap with the fancy new async enumeration pattern.
Edit
Updated with logging to the debugger output and made my OnNext() method async/await as one commenter suggested. You can see it never enters the while() loop.
Further up the call stack I was calling the async method syncronously via the GetAwaiter().GetResult() methods.
Yup, that's a problem.
I did this because in once case I wanted to get the data from within a constructor. I changed that implementation to execute the call using Task.Run() and now the iterators run flawlessly with both implementations.
There are better solutions than blocking on asynchronous code. Using Task.Run is one way to avoid the deadlock, but you still end up with a sub-par user experience (I'm assuming yours is a UI application, since there is a SynchronizationContext).
If the asynchronous enumerator is used to load data for display, then a more proper solution is to (synchronously) initialize the UI to a "Loading..." state, and then update that state as the data is loaded asynchronously. If the asynchronous enumerator is used for something else, you may find some appropriate alternative patterns in my async constructors blog post.

Converting synchrous to asynchrous method in C#

I have gone through several post for converting existing synchronous method to asynchronous. So based on what I have read I am converting the synchronous method to asynchronous like below
Synchronous
public class SomeClass
{
public int DoWork()
{
return DoLongRunningWork();
}
public int DoLongRunningWork()
{
Thread.Sleep(1000);
return 1;
}
}
I converted this to Asynchronous version like below
public class SomeClass
{
public async Task<int> DoWorkAsync()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return await DoLongRunningWorkAsync();
}
public Task<int> DoLongRunningWorkAsync()
{
Thread.Sleep(1000);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return Task.Run(() => 1);
}
}
I am calling this from Main() Method
static void Main()
{
Someclass worker = new SomeClass();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
var result = worker.DoWorkAsync().GetAwaiter().GetResult();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(result);
Console.ReadKey();
}
Is this a correct way to convert synchronous to asynchronous method?
I was expecting Main method's ManagedThreadId will be different than DoWorkAsync and DoLongRunningWorkAsync method's ManagedThreadId. But they are same, why?
I used Thread.Sleep() just to simulate the long running method. As per the suggestions below i should have used Task.Delay() to avoid any confusion.
I dont think i have to put my actual business logic here to understand the concept of async.
As per Stephen Cleary
1> Identify the naturally-asynchronous operations your code is doing.
2>Change the lowest-level API calls to invoke asynchronous APIs (with await) instead of synchronous APIs.
However none of the .Net Libarary methods im using inside LongRunningMethod are naturally-asynchronous or awaitable and also LongRunningMethod is not doing any I/O operation.
Requirement
I have Web API which takes JSON string as input. The JSON needs to be transformed into some C# object. For transformation I am building a C# library which takes JSON string as input and then Transform that JSON string into C# objects based on some rules. The library may take time ( few milliseconds) for Transformation, during this I DO NOT want Web API's main thread to block. The main thread should be free to take any other request while the transformation is going on background thread (some other thread).
public class MyWebApi: ApiController
{
private ILib _myLibrary
public MyWebApi(ILib myLibrary)
{
_myLibrary = myLibrary
}
publi async Task<SomeObject> Transform(string jsonString)
{
// i want to make LongRunningMethod() method awaitable
// or at least it needs to execute on different thread so that
// main thread will be free.
var result = await _myLibrary.LongRunningMethod(jsonString);
return result;
}
}
publi class MyLibrary:ILib
{
// A method that does Transformation
public async Task<SomeObject> LongRunningMethod(string jsonString)
{
var result = new SomeObject();
// parse jsonString here
// and based on some complex rules create SomeObject
// this operation may takes time (lets say few milliseconds)
// i may call some other private methods here or public methods from other library
return result
}
}
based on what I have read I am converting the synchronous method to asynchronous like below
The best way to convert synchronous methods to asynchronous (as I describe in my async brownfield article) is the following:
Identify the naturally-asynchronous operations your code is doing. This is anything that is not running CPU code, e.g., I/O.
Change the lowest-level API calls to invoke asynchronous APIs (with await) instead of synchronous APIs.
Note the compiler warning and change your calling method to be async with a proper (Task/Task<T>) return type. Also add an Async suffix.
Change calling methods to use await, and repeat step (3).
When you run into problems with step (3), check out my articles on async OOP, async MVVM (if applicable), and async brownfield.
Applying these to your code:
Identify the naturally-asynchronous operations your code is doing. This is anything that is not running CPU code, e.g., I/O.
Your lowest-level method has a call to Thread.Sleep, which is not running code. The asynchronous equivalent is Task.Delay.
Change the lowest-level API calls to invoke asynchronous APIs (with await) instead of synchronous APIs.
public int DoLongRunningWork()
{
await Task.Delay(1000);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return 1;
}
Note the compiler warning and change your calling method to be async with a proper (Task/Task<T>) return type. Also add an Async suffix.
public async Task<int> DoLongRunningWorkAsync()
{
await Task.Delay(1000);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return 1;
}
Change calling methods to use await, and repeat step (3).
public int DoWork()
{
return await DoLongRunningWorkAsync();
}
Note the compiler warning and change your calling method to be async with a proper (Task/Task<T>) return type. Also add an Async suffix.
public async Task<int> DoWorkAsync()
{
return await DoLongRunningWorkAsync();
}
Change calling methods to use await, and repeat step (3).
In this case, since Main cannot be async, you'll need to block with GetAwaiter().GetResult(), just like you currently have.
Final result:
public async Task<int> DoWorkAsync()
{
return await DoLongRunningWorkAsync();
}
public async Task<int> DoLongRunningWorkAsync()
{
await Task.Delay(1000);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
return 1;
}
I was expecting Main method's ManagedThreadId will be different than DoWorkAsync and DoLongRunningWorkAsync method's ManagedThreadId. But they are same, why?
"Asynchronous" does NOT mean "runs on a different thread." See my async intro for more details about how async/await works.

How to create a Task which always yields?

In contrast to Task.Wait() or Task.Result, await’ing a Task in C# 5 prevents the thread which executes the wait from lying fallow. Instead, the method using the await keyword needs to be async so that the call of await just makes the method to return a new task which represents the execution of the async method.
But when the await’ed Task completes before the async method has received CPU time again, the await recognizes the Task as finished and thus the async method will return the Task object only at a later time. In some cases this would be later than acceptable because it probably is a common mistake that a developer assumes the await’ing always defers the subsequent statements in his async method.
The mistaken async method’s structure could look like the following:
async Task doSthAsync()
{
var a = await getSthAsync();
// perform a long operation
}
Then sometimes doSthAsync() will return the Task only after a long time.
I know it should rather be written like this:
async Task doSthAsync()
{
var a = await getSthAsync();
await Task.Run(() =>
{
// perform a long operation
};
}
... or that:
async Task doSthAsync()
{
var a = await getSthAsync();
await Task.Yield();
// perform a long operation
}
But I do not find the last two patterns pretty and want to prevent the mistake to occur. I am developing a framework which provides getSthAsync and the first structure shall be common. So getSthAsync should return an Awaitable which always yields like the YieldAwaitable returned by Task.Yield() does.
Unfortunately most features provided by the Task Parallel Library like Task.WhenAll(IEnumerable<Task> tasks) only operate on Tasks so the result of getSthAsync should be a Task.
So is it possible to return a Task which always yields?
First of all, the consumer of an async method shouldn't assume it will "yield" as that's nothing to do with it being async. If the consumer needs to make sure there's an offload to another thread they should use Task.Run to enforce that.
Second of all, I don't see how using Task.Run, or Task.Yield is problematic as it's used inside an async method which returns a Task and not a YieldAwaitable.
If you want to create a Task that behaves like YieldAwaitable you can just use Task.Yield inside an async method:
async Task Yield()
{
await Task.Yield();
}
Edit:
As was mentioned in the comments, this has a race condition where it may not always yield. This race condition is inherent with how Task and TaskAwaiter are implemented. To avoid that you can create your own Task and TaskAwaiter:
public class YieldTask : Task
{
public YieldTask() : base(() => {})
{
Start(TaskScheduler.Default);
}
public new TaskAwaiterWrapper GetAwaiter() => new TaskAwaiterWrapper(base.GetAwaiter());
}
public struct TaskAwaiterWrapper : INotifyCompletion
{
private TaskAwaiter _taskAwaiter;
public TaskAwaiterWrapper(TaskAwaiter taskAwaiter)
{
_taskAwaiter = taskAwaiter;
}
public bool IsCompleted => false;
public void OnCompleted(Action continuation) => _taskAwaiter.OnCompleted(continuation);
public void GetResult() => _taskAwaiter.GetResult();
}
This will create a task that always yields because IsCompleted always returns false. It can be used like this:
public static readonly YieldTask YieldTask = new YieldTask();
private static async Task MainAsync()
{
await YieldTask;
// something
}
Note: I highly discourage anyone from actually doing this kind of thing.
Here is a polished version of i3arnon's YieldTask:
public class YieldTask : Task
{
public YieldTask() : base(() => { },
TaskCreationOptions.RunContinuationsAsynchronously)
=> RunSynchronously();
public new YieldAwaitable.YieldAwaiter GetAwaiter()
=> default;
public new YieldAwaitable ConfigureAwait(bool continueOnCapturedContext)
{
if (!continueOnCapturedContext) throw new NotSupportedException();
return default;
}
}
The YieldTask is immediately completed upon creation, but its awaiter says otherwise. The GetAwaiter().IsCompleted always returns false. This mischief makes the await operator to trigger the desirable asynchronous switch, every time it awaits this task. Actually creating multiple YieldTask instances is redundant. A singleton would work just as well.
There is a problem with this approach though. The underlying methods of the Task class are not virtual, and hiding them with the new modifier means that polymorphism doesn't work. If you store a YieldTask instance to a Task variable, you'll get the default task behavior. This is a considerable drawback for my use case, but I can't see any solution around it.

Categories