Когда lock (SyncObject) может выдавать исключение?
-
06-07-2019 - |
Вопрос
Я написал com-компонент в .NET, и если я попытаюсь заблокировать любой объект любым методом (который вызывается неуправляемым кодом, взаимодействующим с моим com-компонентом) Я получаю исключение.
На данный момент у меня нет точного текста исключения, но это тоже было не очень полезно.
Итак, мой вопрос заключается в том, при каких обстоятельствах блокировка (SyncObject) вызвала бы исключение?Вот некоторые факты:
- SyncObject не равен нулю
- SyncObject еще не заблокирован
Будет ли это иметь какое-либо отношение к вызываемому абоненту, работающему в STA (однопоточная квартира) или MTA (многопоточная квартира)?
Решение
От эта страница:
Каждое получение блокировки может вызвать исключение.Будьте готовы к этому.
Большинство блокировок лениво выделяют событие, если получение блокировки сталкивается с конфликтом, включая мониторы CLR.Это распределение может привести к сбою в условиях нехватки ресурсов, вызывая ООМ, исходящие от входа в шлюз.(Обратите внимание, что типичная неблокирующая спин-блокировка не может завершиться сбоем с помощью OOM, что позволяет использовать ее в некоторых сценариях с ограниченными ресурсами, например, внутри CER.) Аналогично, хост, подобный SQL Server, может выполнять обнаружение взаимоблокировки и даже устранять эти взаимоблокировки, генерируя исключения, исходящие из инструкции Enter, проявляющиеся как System.Runtime.Службы взаимодействия.COMException.
Часто мало что можно сделать в ответ на такое исключение.Но код, чувствительный к надежности и безопасности, который должен надежно справляться со сбоями, должен учитывать этот случай.Нам бы хотелось, чтобы на взаимоблокировки хоста можно было разумно реагировать, но большая часть библиотечного кода не может разумно переместиться в безопасную точку стека, чтобы можно было выполнить откат и повторить операцию.В типичном стеке просто слишком много межбиблиотечного микширования.Вот почему получение монитора на основе таймаута с помощью TryEnter обычно является плохой идеей для предотвращения взаимоблокировки.
Итак, как вы можете прочитать, похоже, что в условиях ограниченных ресурсов мы можем получать исключения, генерируемые методом Ввода монитора, который lock (o) использует внутренне.
Так что, возможно, ваше решение - это что-то вроде ожидания вращения?
{
uint iters = 0;
while (!cond) {
if ((++iters % 50) == 0) {
// Every so often we sleep with a 1ms timeout (see #30 for justification).
Thread.Sleep(1);
} else if (Environment.ProcessorCount == 1) {
// On a single-CPU machine we yield the thread.
Thread.Sleep(0);
} else {
// Issue YIELD instructions to let the other hardware thread move.
Thread.SpinWait(25);
}
}
}
Где cond мог бы быть некоторым
private volatile int cond = 0
используется, например, сВзаимосвязано.Сравните обмен, где вы меняете, например,Нитки.Текущий.Управляемый идентификатор потока или что-то еще, отличное от нуля?