Why can't I use the 'await' operator within the body of a lock statement?
I assume this is either difficult or impossible for the compiler team to implement for some reason.
No, it is not at all difficult or impossible to implement -- the fact that you implemented it yourself is a testament to that fact. Rather, it is an incredibly bad idea and so we don't allow it, so as to protect you from making this mistake.
call to Monitor.Exit within ExitDisposable.Dispose seems to block indefinitely (most of the time) causing deadlocks as other threads attempt to acquire the lock. I suspect the unreliability of my work around and the reason await statements are not allowed in lock statement are somehow related.
Correct, you have discovered why we made it illegal. Awaiting inside a lock is a recipe for producing deadlocks.
I'm sure you can see why: arbitrary code runs between the time the await returns control to the caller and the method resumes. That arbitrary code could be taking out locks that produce lock ordering inversions, and therefore deadlocks.
Worse, the code could resume on another thread (in advanced scenarios; normally you pick up again on the thread that did the await, but not necessarily) in which case the unlock would be unlocking a lock on a different thread than the thread that took out the lock. Is that a good idea? No.
I note that it is also a "worst practice" to do a yield return
inside a lock
, for the same reason. It is legal to do so, but I wish we had made it illegal. We're not going to make the same mistake for "await".
Unable to await in a lock, how do I ensure async variable and method are not accessed from multiple threads?
lock
is a helper API around Monitor
, which is a thread-bound synchronization primitive, which means it isn't suitable for use with await
, because there is no guarantee what thread you'll be on when you come back from an incomplete asynchronous operation.
Ultimately, you need an async-aware synchronization primitive; the most readily available would be SemaphoreSlim
, which has the WaitAsync()
API that you would use to acquire the lock, with a try
/finally
that calls Release()
.
In the code in the question, depending on the code branch you either acquire (only) the semaphore, or release the semaphore; that is almost certainly wrong. Correct usage would be something more like:
await totalThreadLimiter.WaitAsync();
try
{
// some code with "await" here
}
finally
{
totalThreadLimiter.Release();
}
Await operator can only be used within an Async method
You can only use await
in an async
method, and Main
cannot be async
.
You'll have to use your own async
-compatible context, call Wait
on the returned Task
in the Main
method, or just ignore the returned Task
and just block on the call to Read
. Note that Wait
will wrap any exceptions in an AggregateException
.
If you want a good intro, see my async
/await
intro post.
C# Lock and Async Method
No it won't.
lock
is syntactic sugar for Monitor.Enter
and Monitor.Exit
. lock
will keep execution in the method until the lock is released. It does not function like await
in any way, shape or form.
The 'await' operator can only be used within an async lambda expression error
The problem is in the lambda expression you pass to the Select
. If you want to make use of the await
inside the type create, RegionBreif
, you have to pass an async
lambda expression as below:
Select(async r => new RegionBreif
{
IsServiceable = await RegionBreif.checkIfServicable(Context, r.SiteId, r.Id)
})
Why cant I use await?
You need to mark the method that's using await
as being async:
async Task<UserAccount> DoStuff()
{
var DatabaseContext = new ApplicationDbContext();
var thisUserAccount = await DatabaseContext.Users.FirstAsync(u => u.Id == Id);
return thisUserAccount;
}
That's what the error message is telling you.
await operator is being skipped
If it skips over your code like that, chances are it threw an error and went straight into the catch.
If you want to always execute this block
await this.reloadGridsOnAction(contractItemSubSystemIDsList, responce, true);
you might want to have a finally
block after the catch
.
Related Topics
Any Decent C# Profilers Out There
Best Way to Specify Whitespace in a String.Split Operation
How to Detect the Currently Pressed Key
Creating Application Shortcut in a Directory
Capture the Screen into a Bitmap
How to Register a Global Hot Key to Say Ctrl+Shift+(Letter) Using Wpf and .Net 3.5
Easiest Way to Compare Arrays in C#
How to Set Custom JSONserializersettings for JSON.Net in ASP.NET Web API
Allow Windows Service to Interact with Desktop
Can't Get Czech Characters While Generating a PDF
Remove Weird Characters ( a with Hat) from SQL Server Varchar Column
What Is the Correct Way to Use JSON.Net to Parse Stream of JSON Objects
How to Correctly Implement a Backgroundworker with Progressbar Updates
Why File.Readalllinesasync() Blocks the UI Thread
System.Unauthorizedaccessexception While Running .Exe Under Program Files