Async Lock Not Allowed

Async lock not allowed

Looks like the problem that you have is that threads will block while acquiring the lock, so your method is not completely async. To solve this you can use SemaphoreSlim.WaitAsync

private readonly SemaphoreSlim readLock = new SemaphoreSlim(1, 1); 
public async Task UpdateDetailsAsync()
{
//I want every request to wait their turn before requesting (using the connection)
//to prevent a read call from catching any data from another request
await readLock.WaitAsync();
try
{
Details details = await connection.GetDetailsAsync();
detailsListBox.Items = details;
}
finally
{
readLock.Release();
}
}

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();
}

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.

How to use async-lock in nodejs app to lock a /get resource function

If you look at the docs of the async-lock package, you will notice that the acquire function has the following signature

acquire(
key,
executeFunction,
callbackFunction,
options);

where the executeFunction itself, has the signature

function(done) {...}

and done is a callback, which is used to call the callbackFunction once the work your critical section is done, and the lock can be released. You are omitting the done parameter and thus, not calling the callbackFunction manually. So it's called (and therefore the lock is released) once the executeFunction is finished. And as the setTimeout in your execution function is of course also async, it won't delay the executionFunction.

So the correct way to use it, is as follows

lock.acquire(
synchonizationKey,
function (done) { // <----- new parameter for the function
console.log("--------------Request ", id, " lockAquired");

setTimeout(function () {
console.log("--------------Request ", id, " Done");
done(); // <---- call the callback, once the lock can be released
}, 3000);
},
function (err, ret) {
console.log("--------------Request ", id, " lockReleased");
res.send({ id: id });
},
{});

This leads to the following output

--------------Request  1  arrived
--------------Request 1 lockAquired
--------------Request 2 arrived
--------------Request 3 arrived
--------------Request 4 arrived
--------------Request 1 Done
--------------Request 1 lockReleased
--------------Request 2 lockAquired
--------------Request 2 Done
--------------Request 2 lockReleased
--------------Request 3 lockAquired
--------------Request 3 Done
--------------Request 3 lockReleased
--------------Request 4 lockAquired
--------------Request 4 Done
--------------Request 4 lockReleased

Simple Lock That returns false for concurrent calls - javascript

Promise execution is not always guaranteed to stop immediately after resolving or rejecting; you'll have to return a boolean after you check the lock and exit or continue the promise accordingly.

Run the below snippet; it's an example having 3 buttons with the same promise and a 3 seconds delay. When one button is running all the others can not execute.

class Lock {  constructor() {    this.locked = false;  }
lock(resolve) { if (this.locked) { resolve(false); return false; } this.locked = true return true; }
release(resolve) { this.locked = false; resolve(true) }}
let lock = new Lock();
function myFunction({ resultEl }) { resultEl.textContent = "Is running"; return new Promise(resolve => { // Check if it's locked if (!lock.lock(resolve)) { // If it is, return and exit the function even if the promise is already resolved return; }
// do something - this takes time includes some api calls and db operations // just wait 3 seconds for demontration setTimeout(() => { lock.release(resolve); }, 3000); })}
async function callSite() { this.disabled = true;
const executed = await myFunction({ resultEl : this.nextSibling }); this.disabled = false;
if (executed) { this.nextSibling.textContent = `Finished at ${(new Date).getTime()}`; } else { this.nextSibling.textContent = `Was NOT executed at ${(new Date).getTime()}`; }}
document.getElementById('a-button').addEventListener('click', callSite);document.getElementById('b-button').addEventListener('click', callSite);document.getElementById('c-button').addEventListener('click', callSite);
div {  margin-bottom: 10px;}
button { margin-right: 5px;}
<div>  <button id="a-button">Run A</button><span></span></div>
<div> <button id="b-button">Run B</button><span></span></div>
<div> <button id="c-button">Run C</button><span></span></div>

How to refactor 'lock' to 'async/await'?

You could use SemaphoreSlim, but if there's a lot of it, the AsyncLock library will probably make the conversion much easier (and cleaner).

Just go with the AsyncLock library and relax.

Javascript async-mutex does not seem to lock properly

The reason for this is because the "state" (no pun intended) of the stuff state is uncertain at the time of running setState, due to the nature of setStuff and state setters in general being asynchronous.

The solution is to

a) use await because in any case the mutex lock acquisition is a promise

b) pass a lambda function into setStuff that guarantees the state of stuff will be up to date, as opposed to just assuming stuff will be up to date (which it won't be)

    uppy.on('upload-error',  async (_, response) => {
await mutex.acquire().then((release) => {
setStuff((prevState => {
return prevState.concat('test');
}));
release();
});
})

For more information, check out https://stackoverflow.com/a/44726537/8652920



Related Topics



Leave a reply



Submit