Anawait expression cannot be used in a synchronous function, in a queryexpression, in the catch or finally block of an exception handlingstatement, in the block of a lock statement, or in an unsafe context.
However this does not work as expected. The 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.
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.
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".
Keep hold of the lock, only releasing it at the end of the block.
This is a really bad idea as you don't know how long the asynchronous operation is going to take. You should only hold locks for minimal amounts of time. It's also potentially impossible, as a thread owns a lock, not a method - and you may not even execute the rest of the asynchronous method on the same thread (depending on the task scheduler).
Release the lock in the await, and reacquire it when the await returns
This violates the principle of least astonishment IMO, where the asynchronous method should behave as closely as possible like the equivalent synchronous code - unless you use Monitor.Wait in a lock block, you expect to own the lock for the duration of the block.
So basically there are two competing requirements here - you shouldn't be trying to do the first here, and if you want to take the second approach you can make the code much clearer by having two separated lock blocks separated by the await expression:
This is especially true for event handlers, because for many events you don't have any clue about whats happening after you return from the event handler.One thing that might actually happen is, that the async method you are awaiting in the first event handler, gets called from another event handler still on thesame thread.
Here is a real scenario I came across in a windows 8 App store app:My app has two frames: coming into and leaving from a frame I want to load/safe some data to file/storage.OnNavigatedTo/From events are used for the saving and loading. The saving and loading is done by some async utility function (like ).When navigating from frame 1 to frame 2 or in the other direction, the async load and safe operations are called and awaited.The event handlers become async returning void => they cant be awaited.
However, the first file open operation (lets says: inside a save function) of the utility is async tooand so the first await returns control to the framework, which sometime later calls the other utility (load) via the second event handler.The load now tries to open the same file and ifthe file is open by now for the save operation, fails with an ACCESSDENIED exception.
I created a MutexAsyncable class, inspired by Stephen Toub's AsyncLock implementation (discussion at this blog post), which can be used as a drop-in replacement for a lock statement in either sync or async code:
I also created an extended SemaphoreLocker class, inspired by this answer, which can be a general-purpose replacement for lock, usable either synchronously or asynchronously. It is less efficient than the above MutexAsyncable and allocates more resources, although it has the benefit of forcing the worker code to release the lock once it's finished (technically, the IDisposable returned by the MutexAsyncable could not get disposed by calling code and cause deadlock). It also has extra try/finally code to deal with the possibility of ThreadAbortException, so should be usable in earlier .NET versions:
The Poison Cabinet can be opened using the code 16-75-60. Unlocking it allows you access to the Nova-6 Poison, one of the solutions in the story mission "Desperate Measures". Note that this code is fixed and does not change per playthrough.
To get the code, you need to go to Kravchenko's room and access his computer. There, you need to open the Nova-6 files to get the clue to the code. The clues that you get from the computer are S, Re, Nd, the elements that compose Nova-6.
Just behind the computer and beside the locker is a periodic table of elements. Use this and check the atomic numbers of the elements. When combined, the 3 atomic numbers make a 6-digit code that opens up the Poison Cabinet.
No, asyncio.run() does not violate the async model. It is a helper that takes care of a bunch of bookkeeping around creating and finalizing event loops and it captures the best practice. Your proposed helper would be the opposite of best practice.
For example. You run two asynchronous tasks, A and B. Task A calls a third-party asynchronous function foo() which uses an asynchronous lock to guard access to some complex data. Task B calls a synchronous function bar() which calls the same asynchronous function foo() from a synchronous code. You, as a user, have no idea what locking is used in foo(). If the the lock is acquired in task A, and then the execution is switched to task B which calls bar() which calls foo() which tries to acquire the lock, we have a deadlock, because you cannot switch from task B to task A while executing a synchronous code bar(). What is worse, it can happen random and very rarely, so you will miss this in your tests and it can be hard to reproduce the problem. But if it happen, it will just deadlock your program, without any reporting.
If the the lock is acquired in task A, and then the execution is switched to task B which calls bar() which calls foo() which tries to acquire the lock, we have a deadlock, because you cannot switch from task B to task A while executing a synchronous code bar().
A synchronous function called in task B has nothing to do with asynchronous locking, you cannot do anything with asynchronous locks from a sync code, and you knows nothing about this particular lock which is an implementation detail of third-party code.
There is no problem with using foo() in an asynchronous code, because if it need to acquire a lock which is currently blocked, the execution is just switched to the task which holds the lock, and finally it will be released. The problem with calling an asynchronous code from synchronous code is that it is not possible to switch to that task and resolve blocking.
If you were just a Discourse newbie, I would just have muted the thread at this point, but I know you as a thoughtful, intelligent and experienced contributor in the typing world, so I hope that further dialog is still possible, and we can help you understand asyncio a little better. (I hope that my example above is enlightening.)
And yes, any time you yield inside a critical section, you are implying that (a) other tasks can run, but (b) no other task can run this same critical section. And mixing that with blocking calls that require the same critical section, without threading, is asking for trouble.
I've been researching alot of the smart home locks and these look like they're going to be awesome as we'll be managing our property from afar (rental is in FL and we live in Chicago). Some of the ones that I'm considering:
Is it financially beneficial to host remotely? I ask because I see so many stories about hosts who do what you are planning on doing and its one horror story after the next. Will you have a co-host near the listing? I opted out of the remote lock because people just arent that techno-savvy while traveling and the price to install and upkeep was just too high. Its not the 90% of guests that do it perfectly that I worry about, but the 10% of guests that take up 90% of your time. There were too many unknowns and things that could go wrong with the remote lock. Instead I settled on a simple Schlage keyless entry lock which works fine, but its quirky. It'll lock automatically once the door is closed sometimes, but not all the times. Sometimes after the guest checks out I'll arrive to my place to find the door unlocked. Thankfully I'm down the street and I can check on it at anytime, but it scares me to think what if I was a remote host.
c80f0f1006