Учись программированию на C++ Builder бесплатно!

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

Параллельно выполняемые нити работают в адресном пространстве одного процесса и могут иметь доступ к глобальным переменным этого процесса. Одним из способов создания приложения с несколькими потоками является использование компонента типа TThread. Этот компонент отсутствует в палитре библиотеки. TThread - это абстрактный класс, позволяющий создать в приложении отдельную нить выполнения. Для того чтобы ввести TThread в свое приложение, надо выполнить команду File | New | Other и в открывшемся окне Депозитария на странице New выбрать пиктограмму Thread Object. Вам будет задан вопрос об имени (Class Name) создаваемого класса, наследующего TThread. Укажите любое имя (например, T) и в ваш проект добавится новый модуль.

Созданный C++Builder модуль, содержит заготовку класса с введенным вами именем (в нашем пример - T), наследующего TThread. Можно добавлять в него любые свойства и методы, учитывая отмеченные в комментариях области видимости. Процедура Execute, является основной процедурой нити. При ее окончании завершается и выполнение данной нити приложения.

Класс наследует от TThread ряд методов. Прежде всего это конструктор, создающий объект нити:

__fastcall TThread(bool CreateSuspended);

Параметр CreateSuspended конструктора определяет способ выполнения нити. Если CreateSuspended = false, то выполнение процедуры Execute начинается немедленно после создания объекта. Если CreateSuspended = true, то выполнение начнется только после того, как будет вызван метод Resume:

void __fastcall Resume(void);

Конструктор TThread не должен вызываться в приложении явным образом. Для создания объекта класса TThread, как и для всех классов VCL, надо использовать операцию new. Например:

T *SecondProcess = new T(true);
SecondProcess->Resume();

Нужно написать функцию, выполняющую необходимые действия с компонентами VCL. Дадим ей имя Work. Тогда нужно включить ее объявление в класс нити, например, в раздел private, даете в файле реализации ее описание, а процедура Execute в этом случае может, например, состоять из единственного оператора Synchronize(Work).

Нормальное завершение выполнения нити происходит при завершении процедуры Execute. Однако возможно и досрочное завершение выполнения нити. Для этого в ее процедуру Execute должна быть введена проверка булева свойства Terminated (завершено). Нормально это свойство равно false. Но если какая-то внешняя нить вызвала метод Terminate объекта данной нити, то Terminated становится равным true. Если предполагается возможность такого завершения выполнения нити, то процедура Execute должна периодически проверять значение Terminate и при получении значения true должна завершаться. Например:

void __fastcall T::Execute()
{
do
{
...
}
while (!Terminated);
}

Метод Terminate обеспечивает «мягкое» завершение нити. Процедура Execute сама решает, в какой момент ей удобно завершить выполнение. Имеется и более грубая функция API Windows - TerminateThread, вызывающая немедленное завершение выполнения нити. Например, оператор прервет выполнение объекта нити с именем SecondProcess:

TerminateThread((void *)SecondProcess->Handle,0);

В этом операторе использовано свойство Handle (дескриптор) нити, позволяющее обращаться к функциям API Windows. Второй параметр функции TerminateThread задает код завершения нити. Этот код можно прочитать в свойстве Return Value объекта нити.

Поделиться