Главная » C++, C++ Builder » Простой пример потока в CBuilder

0

В нашем первом примере мы начнем с внутренних особенностей работы с потоками. Мы создадим простую форму, которая использует поток для обновления текста на экране. Форма позволит вам приостанавливать (pause), вновь запускать (resume) и останавливать (stop) выполнение потока. В то же время поток будет отображать числа на экране. Мы исследуем процесс создания потока и добавления объекта «поток» в вашу программу.

На рис. 13.1 показана форма, которую мы будем использовать в данном примере  потока.  Как видите, на ней находится одна метка и три кнопки.

Рис. 13.1. Форма простого примера потоков

Добавление нового потока

Первым делом в приложении, использующем потоки, было бы неплохо узнать, как же добавить поток. Вы, наверное, видели класс TThread в документации к CBuilder. Этот класс служит для представления потоков в системе. К сожалению, добавление нового потока немного сложнее, чем создание нового объекта «поток» оператором new.

Потоки содержат метод, который реализует всю необходимую обработку потока. Этот метод (Execute) вызывается при старте потока и должен работать, пока поток жив. Когда метод Execute возвращает управление, то поток выходит или  умирает.  Таким  образом,  вам  нужно переопределить метод Execute так, чтобы он делал то, что вам нужно. Но  чтобы можно было переопределить метод, вам необходимо унаследовать свой собственный класс от класса TThread, и именно этим мы и займемся. Вы определите класс, наследуемый от TThread, и напишете метод Execute для этого порожденного класса.

В  CBuilder  очень  легко  создавать  классы,  наследуемые  от  TThread,  создавая  новый  объект

«поток». Для этого выберите команду File д New и элемент Thread Object (потоковый объект) на первой странице диалога New Items. При выборе этого объекта появится вторичное окно диалога с запросом о новом имени вашего потокового класса. В данном случае укажите имя TCheckThread, так как мы будем проверять некоторое значение и отображать его. Когда вы нажмете на кнопку OK, класс TCheckThread будет сгенерирован в исходном файле Unit2.cpp (а также  в заголовочном файле Unit2.h). Вот так выглядит этот класс, сгенерированный CBuilder:

//——————————————————

#include <vcl\vcl.h>

#pragma hdrstop

#include "Unit2.h"

//——————————————————

// Important: Methods and properties of objects in VCL can

// only be used in a method called using Synchronize,

// for example:

//  Synchronize(UpdateCaption);

// where UpdateCaption could look like:

//

// void      fastcall TCheckThread::UpdateCaption()

// {

// Form1->Caption = "Updated in a thread";

// }

//—————————————————–

__fastcall TCheckThread::TCheckThread(bool CreateSuspended)

: TThread (CreateSuspended)

{

}

//—————————————————–

void __fastcall TCheckThread::Execute()

{

//—- Place thread code here —-

}

//—————————————————–

Как  видите,  потоковый  класс,  сгенерированный  мастером,  описан  весьма  полно.  Он  ничего  не делает, но готов к работе. Чтобы он что-то делал, вам нужно только лишь написать метод Execute.

В нашем первом примере интересно было бы изучить разные методы класса потока.  Именно поэтому наш метод Execute крайне прост, он считает до 10000 снова и снова. Мы хотим проиллюстрировать скорость работы кода потока, связь потока с окружающим миром и научить вас писать код потока. Держа все это в уме, добавьте следующий код в метод Execute:

void __fastcall TCheckThread::Execute()

{

while ( !Terminated )

{

Synchronize(UpdateLabel1);

}

MessageBox(NULL, "Все сделано!", "Информация", MB_OK);

}

Кроме метода Execute, нам нужно еще обновить два метода. Во-первых, конструктор класса. Вот код инициализации, который нужно добавить в конструктор:

__fastcall TCheckThread::TCheckThread(bool CreateSuspended)

: TThread (CreateSuspended)

{

pLabel = NULL; nCount = 0;

}

Здесь мы устанавливаем начальные значения для указателя на метку, в которую мы будем передавать показания нашего счетчика, а также  для самого счетчика, который будет содержать значения от 0 до 10 000 и будет постоянно увеличиваться. Кроме этого, нам нужен метод, чтобы присвоить значение нашему указателю на метку:

void __fastcall TCheckThread::AssignLabel(TLabel *pL)

{

pLabel = pL;

}

Метод Synchronize предоставляет вам способ избежать всех этих проблем, связанных с многопоточностью, когда один и тот же объект пытаются изменить из разных потоков в приложении. Когда вы работаете в главном потоке (самом приложении) с объектом VCL, то вам

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

У метода Synchronize единственный аргумент типа TThreadMethod. Это просто указатель на функцию-член класса потока, у которой нет параметров и которая ничего не возвращает. Эта функция должна быть как можно более быстрой, чтобы взаимодействие между потоками происходило безболезненно. При вызове Synchronize будет работать только переданный метод, и ничего более.

Итак, весь этот код приводит к вызову метода UpdatLabel, который собственно и делает  всю работу в классе потока. Это весьма простой метод, как видно из листинга:

void __fastcall TCheckThread::UpdateLabel(void)

{

if ( pLabel )

pLabel->Caption = nCount; if ( nCount < 10000 ) nCount ++;

else

nCount = 0;

}

Теперь, имея весь этот код класса потока, пора модифицировать класс формы: создавать поток, а затем работать с ним. Давайте обратим наше внимание на эту задачу.

Источник: Теллес М. – Borland C++ Builder. Библиотека программиста – 1998

По теме:

  • Комментарии