Когда блокировка (syncObject) может вызвать исключение? - PullRequest
0 голосов
/ 28 ноября 2009

Я написал com-компонент в .NET, и если я пытаюсь установить блокировку любого объекта в любом методе (который вызывается неуправляемым кодом, взаимодействующим с моим com-компонентом), я получаю исключение.

У меня нет точного текста исключения на данный момент, но это также не очень помогло.

Итак, мой вопрос: при каких обстоятельствах блокировка (syncObject) может вызвать исключение? Вот некоторые факты:

  • syncObject не является нулевым
  • syncObject еще не заблокирован

Будет ли это иметь какое-либо отношение к вызываемому абоненту, работающему в STA (однопоточные апартаменты) или MTA (многопоточные квартиры)?

1 Ответ

2 голосов
/ 30 ноября 2009

С этой страницы :

Каждое приобретение блокировки может вызвать исключение. Будьте готовы к этому.

Большинство блокировок лениво выделяют событие, если обнаружение блокировки сталкивается с конфликтом, включая мониторы CLR. Это распределение может завершиться ошибкой в ​​условиях низкого ресурса, что приведет к появлению OOM от входа в замок. (Обратите внимание, что типичная неблокирующая спин-блокировка не может выйти из строя с OOM, что позволяет использовать ее в некоторых сценариях с ограниченными ресурсами, например внутри CER.) Точно так же хост, такой как SQL Server, может выполнять обнаружение взаимоблокировок и даже прерывать эти взаимоблокировки с помощью генерация исключений, которые происходят из оператора Enter, проявляющегося как исключение System.Runtime.InteropServices.COMException.

Часто не так много можно сделать в ответ на такое исключение. Но код, чувствительный к надежности и безопасности, который должен иметь дело с ошибками, должен учитывать этот случай. Нам бы хотелось, чтобы в этом случае можно было разумно реагировать на взаимные блокировки хоста, но большая часть кода библиотеки не может интеллектуально развернуть безопасную точку в стеке, чтобы она могла откатиться и повторить операцию. В типичном стеке просто слишком много кросс-библиотечного перемешивания. Вот почему приобретение монитора на основе тайм-аута с TryEnter, как правило, является плохой идеей для предотвращения тупиков.

Итак, как вы можете прочитать, кажется, что в условиях ограниченных ресурсов мы можем получить исключения из метода Enter, который Monitor использует внутренне. 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

используется, например, с Interlocked.CompareExchange, где вы меняете, например, на. Thread.Current.ManagedThreadID или что-то еще, отличное от нуля?

...