Скачиваний:
100
Добавлен:
01.05.2014
Размер:
1.56 Mб
Скачать

Манипуляция ресурсами в dll

Все сказанное в этом разделе применимо не только к серверу автоматизации, но и при вызове любой DLL. Следует обратить внимание на то, что DLL и приложение, которое ее вызывает, имеют независимые менеджеры памяти (memory manager). Поэтому, если память выделяется в приложении, абсолютно недопустимо освобождать ресурсы в DLL, и наоборот, если память выделяется в DLL, недопустимо высвобождать ресурсы в приложении.

Типичный пример вызова DLL приведен ниже:

int i, N;

int *Data;

Data = new int[1000];

N = CalculateSum (Data, 1000);

delete Data;

Соответственно в DLL имеется метод:

int CalculateSum (int *pData, int Count)

{

int s = 0;

for (int i = 0; i < Count; i++)

{

s += pData[i];

}

return s;

}

В приведенном примере следует обратить внимание на то, что методы newиdeleteнаходятся в вызывающем приложении. Попытка использоватьdeleteв DLL приводит к ошибке Access Violation. В данном примере ресурсы выделяются в приложении и затем используются в DLL. Если же необходимо поступить наоборот, то есть выделить ресурсы в DLL, а затем использовать их в приложении, то в DLL необходимо предусмотреть вызов дополнительного метода для освобождения ресурсов. Типичная реализация выглядит следующим образом:

void CreateData (int *OutData)

{

OutData = GlobalAlloc (0, 1000 * sizeof (int));

for (int i = 0; i < 1000; i++)

{

OutData[i] = i;

}

}

void ReleaseData (int *OutData)

{

if (OutData)

{

GlobalFree (OutData);

}

}

Оба эти модуля помещаются в DLL, основное приложение сначала вызывает метод CreateData, а после окончания работы с ресурсами обязано вызвать методReleaseData.

Работа внутреннего сервера автоматизации в многопоточном режиме Понятие многопоточности. Синхронизация

Понятие многопоточности тесно связано с возможностью выполнения нескольких приложений одновременно. Еще в Windows 3.1 была реализована такая возможность. Однако если какое-либо приложение выполняло долговременные операции, то до окончания вычислений пользователь не мог обратиться к другим приложениям. Такая ситуация называется захватом процессора (processor capture).

В Windows 95 и Windows NT уже была реализована так называемая "истинная   многозадачность. Ее идея заключается в следующем: спустя определенный в системе квант времени запоминаются состояния регистров процессора и затем они заменяются данными для другой задачи. Далее вычисления продолжаются для новой задачи. Когда вновь наступает очередь выполнения первой задачи, содержимое регистров процессора восстанавливается и продолжаются вычисления.

Соответственно возникает вопрос: а можно ли в рамках одного приложения запустить несколько задач? Действительно, получается удобный пользовательский интерфейс: приложение печатает отчет, одновременно проводит статистическую обработку данных и еще при этом дает возможность пользователю просматривать данные. Такой тип вычислений называют многопоточным (multi-threading). Русский перевод этого термина не очень удачен, так как потоки вычислений можно перепутать с потоками данных (streams). В этой главе речь будет идти только о потоках вычислений (threads).

При запуске любого приложения всегда создастся один поток вычислений, который называют главным. Далее приложение может создать дополнительные потоки вычислений. Наиболее просто это можно сделать создав объект TThread. МетодExecute, определенный и таком объекте, будет выполняться уже в другом потоке. Таких объектов может быть создано несколько, но не рекомендуется для одного приложения создавать их более шестнадцати.

Одно из важнейших свойств потоков вычислений - их приоритетность. Приоритетность определяет, сколько квантов времени будет выделяться процессу. Чем выше приоритетность, тем больше таких квантов времени будет выделяться такому потоку. Приоритетность определяется относитсльно приоритетности главного потока и может принимать значения tpIdle,tpLowest,tpLower,tpNormal,tpHigher,tpHighest,tpTimcCritical. Последний тип приоритетности применяется только в специальных приложениях. Дело и том, что многие методы ядра Windows представляют собой асинхронные процессы с приоритетомtpHighest. Это значит, что если будут вызваны некоторые методы Windows API, то такое приложение захочет выполнять задачу дальше, не дожидаясь окончания их выполнения, что, как правило, приводит к генерации исключения.

Программист никогда не должен предполагать, что какой-либо поток завершит свою работу раньше другого. Казалось бы, если два потока производят примерно поровну вычислений и были запущены одновременно с приоритетами tpLowestиtpHighest, то следует ожидать, что второй поток завершится раньше, и заманчиво попытаться использовать результаты его вычислений в финальной стадии вычислений первого потока. Но на компьютере с несколькими процессорами при малом числе запущенных приложений эти потоки будут выполняться на разных процессорах со 100-процентным предоставлением времени каждому из них.

Таким образом, мы приблизились к понятию синхронизации. Предположим, имеется два потока: один считывает показания датчиков, формирует массив данных и заносит данные в память компьютера, а другой использует эти данные для формирования диаграммы и отображает ее на мониторе. Каждый из этих потоков может прервать работу другого в любой момент. Если произойдет прерывание первого потока в момент занесения данных, то часть массива будет с новыми данными, а часть - со старыми.

Понятно, что первому потоку следует запретить заносить данные в глобальные переменные, пока второй поток их считывает, и наоборот, если второй поток читает эти данные, то первый должен подождать с их формированием. Такое поведение двух потоков называется синхронизацией. Объект TThreadимеет методSynchronize, который позволяет синхронизировать главный поток приложения с потоком, созданным данным объектом. При вызове какой-либо процедуры через этот метод главный поток приостанавливает свою работу и дожидается окончания работы процедуры, вызванной в методеSynchronize.

Однако метод Synchronizeнеприменим, если необходимо синхронизировать работу двух неосновных потоков. Для их синхронизации используются семафоры, мьютексы и критические секции. В данной главе будут обсуждаться только критические секции.