Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DiVM / OSISP / ОCиСП-Часть3 / Теория / Теория (ОСиСП).doc
Скачиваний:
37
Добавлен:
11.05.2015
Размер:
616.96 Кб
Скачать

Исключительные ситуации

Это понятие внедрено в саму платформу .Net, но по использованию отличается от С:

в C#, Java, Delphi есть блок try…finally. Этот оператор используется в 100 раз чаще, чем try…catch.

В C# есть специальный предопределенный класс Exception, от которого наследуются все остальные исключительные ситуации. Вызываются исключительные ситуации так:

throw new Exception (“Can not access database”);

текст – описание исключительной ситуации – должен быть максимально подробным, написанным без сокращений и членораздельно указывать конкретную причину ошибки, чтобы, получив это сообщение, сразу понять причину.

Для обработки исключительных ситуаций существует try…catch:

try

{

Op1 ( );

Op2 ( );

}

catch (Exception e) // для обработки всех исключений

(

Console.WriteLine (e.Message); // в Message помещается текст из

} // throw new Exception (…);

Обработка каждого сообщения при построении специальных библиотек помещается в try…catch, чтобы в случае исключительной ситуации появилось окно, а дальше продолжилась обработка сообщений. При написании программ используется стандартные процедуры обработки исключительных ситуаций из визуальных библиотек. Надо заботиться о защите от исключительных ситуаций с помощью try…finally. Они используются:

  1. когда происходит вход/выход в/из критическую секцию (выход – в finally)

  2. освобождение объекта с помощью dispose (конструирование объекта – до try, dispose в finally)

В секции try выполняется любая работа. Создавать объект надо до try, а копировать его внутри:

Object o = new MyObject ( );

try

{

o.Do ( );

}

finally

{

o.Dispose ( );

}

Если возникает исключение в самом конструкторе, то нет для кого вызывать Dispose.

Исключительные ситуации надо программировать при многопоточности. Если исключительная ситуация в потоке, то поток прерывается, прерывается выполнение всей программы, и программа завершается с ошибкой.

Метод потока всегда должен быть защищен от исключительных ситуаций. При использовании пула потоков (ThreadPool), каждый вызываемый делегат дополнительно обрамляется блоком try…catch. При ошибке поток приостанавливается преждевременно, и в его свойстве состояния записывается объект исключения, который возник в потоке. При использовании объектов класса Thread каждый делегат, который передается в thread, надо объявлять с catch (т.е. надо это делать программисту, а при использовании пула система берет на себя).

Object o = null;

try

{

o = new MyObject ( );

o.Do ( );

}

finally

{

o.Dispose ( );

}

Это грубая ошибка, т.к. при ошибке конструктора в о будет null, а потом Dispose будет применяться к o==null (using вызывает Dispose автоматически).

(отступление)

Для volatile-переменных не используется кэширование.

Для volatile-переменных гарантируется чтение/запись за одну машинную операцию. При работе с volatile-переменными могут быть ошибки. Логически переменные читают/записываются за одну операцию, я если переменная занимает много байт, то чтение/запись может выполняться за две инструкции. Если поток читает, то он читает 4 байта, а другие 4 байта не прочитает. Или если пишет другой поток, то может часть записать, а другой не запишет. Поэтому можно использовать критические секции. Но это неэффективно: если вход в критическую секцию, то происходит «ресинхронизация КЭШей процессора» (производится доступ к функции ОС-мы). Вход в критическую секцию занимает намного больше времени (в 1000 раз), чем работа с переменной в критической секции. Доступ к переменной замедляется при рассинхронизации.

Второй подход решения проблемы (без критической секции):

Interlocked XXXX

InterlockedExchange - установка значения

InterlockedRead - чтение

InterlockedIncrement - увеличение на 1

InterlockedDecrement - уменьшение на 1

Обеспечивают атомарное выполнение операций. Эти операции обращаются к ОС, но они не входят в критическую секцию.