Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, nigh, Вы писали:
N>>Это, вроде отцы-основатели не рекомендуют делать. Они даже не рекмендуют больше lock использовать https://blogs.msdn.microsoft.com/ericlippert/2009/03/06/locks-and-exceptions-do-not-mix/
AVK>Ну, если судить по твоей ссылке, то "не рекомендуют" сильно сказано. Кроме того, в случае с RWLock это не борьба с исключением, а просто способ указать в коде scope, в котором лок действует. Примерно как Html.BeginForm в MVC.
Да нет, там все гораздо глубже. Основная мысль в том, что Disposable и try-finally для семантики локов не подходят и создают ложное ощущение безопасности.
В случае с rwlock, если в процессе выполнения операции внутри using возникнет исключение, finally-блок радостно разблокирует заблокированный ресурс и вы получите букет с race conditions, unprecitable behavior и т. д. (т.е. unlock произойдет тогда, когда вы его не ожидали, а не должен был произойти в принципе)
Причем, самое ужасное, что такой дизайн кода получается неявно (в случае явного вызова lock / unlock и отсутствия implicit try/finally в глаза сразу бросаются вопросы "а что будет если тут будет exception?")
using(GetRWLock())
{
UpdateJournal(AccountA, AccountB, 100)
AddMoney(AccountA, 100)
WithdrawMoney(AccountB, 100) //throw an exception here, all other threads now receive an account in an incorrect state
}
var lc = GetRWLock();
lc.wlock();
UpdateJournal(AccountA, AccountB, 100)
AddMoney(AccountA, 100)
WithdrawMoney(AccountB, 100) //throw an exception here, will never unlock unless proper recovery is done - likely a deadlock, but no further data corruption by other threads
rwlock.unlock();