Для того, чтобы создать свой класс активного объекта, его нужно унаследовать от классов Cntm::ActiveRefBase, Cntm::ActiveRefBaseEx, Cntm::ActiveSynchroRefBase или Cntm::ActiveSynchroRefBaseEx (эти объекты добавляют класс Cntm::ActiveObject как примесь к соответствующей реализации подсчета ссылок или реализации синхронизации).
Средства, предоставляемые базовыми классами активных объектов - управление потоками активных объектов (класс Cntm::ActiveThread). Активные объекты могут создавать свои потоки с помощью метода Cntm::ActiveObject::StartThread()() или Cntm::ActiveThread::Start()(). В качестве потока выступает какой-либо метод объекта, которому при запуске можно передать любые аргументы. Потоки активных объектов являются единицами выполнения (класс Cntm::ActiveThread унаследован от Cntm::ExecutionUnit) и взаимодействие с потоками производится через хэндлы потоков (класс Cntm::ActiveThreadHandle), которые возвращаются как результат запуска. Как любая единица выполнения, поток активного объекта м.б. принудительно остановлен, для этого через хэндл ему посылается сигнал останова (процедуры останова подробно описаны в классе Cntm::ExecutionUnit).
Пример:
class Class1: public ActiveSynchroRefBase { ActiveThreadHandle hdl; void Thread1(int a, string s) { ... } void Start() { StartThread(&Class1::Thread1)(45, "Text"); hdl = ActiveThread::Start(this, &Class1::Thread1)(45, "Text"); } };
Выше говорилось, что поток активного объекта не создает новую ссылку на объект, а также, что поток завершаетмя после перехода объекта в удаляемое состояние (т.е. может выполняться, когда поток находится как в рабочем, так и в удаляемомм состоянии). Если потоку в процессе выполнения требуется ссылочный указатель на свой объект, то он его может получить из обычного, например, из this. При этом следует помнить, что если объект находится в удаляемом состоянии, то преобразование из обычного в ссылочный будет приводить к тому, что ссылочный указатель примет значение NULL.
Для того, чтобы объект при отсутствии на него ссылок смог уничтожиться, все его потоки должны остановиться. Для обнаружения сигнала останова в потоках можно использовать стандартные средства, предлагаемые классом Cntm::ActiveThread - Cntm::ActiveThread::Terminated() и Cntm::ActiveThread::CheckTerminating(). Первый просто возвращает значение флага останова потока, второй проверяет, и если он установлен, то генерирует специальное исключение Cntm::ActiveThreadTerminatingSignal.
Использование Using-объектов. Using-объекты (класс Cntm::Using, пакет Concurrency) - это scoped-объекты, наподобии auto_ptr и т.п., являющиеся по сути ссылочными указателями на активные объекты. Using-объекты преследуют 2 цели: 1 - при создании они проверяют флаг завершения потока и переданный ссылочный указатель на NULL (т.е. объект уже находится в удаляемом состоянии), если какое либо из этих условий истинно, то генерируется специальное исключение Cntm::ActiveThreadTerminatingSignal. 2 цель - хранить полученный ссылочный указатель на всем протяжении времени существования Using-объекта, т.о. гарантируется, что при выполнении кода, находящегося между созданием и деинициализацией Using-объекта активный объект не перейдет в удаляемое состояние. Для синхрообъектов имеются специальные Using-объекты, объединенные с синхросекциями - классы Cntm::UsingSync и Cntm::UsingReentrantSync, которые, кроме всего прочего, производят вход в синхропространство, к которому принадлежит активный синхрообъект. Пример метода активного объекта, выполняющегося в потоке:
void Thread1(int a, string s) { while (true) // Бесконечный цикл, в котором выполяниются повторяющиеся операции. { sleep(1); ... // Вход в Using-секцию. Либо вход будет успешный, либо, если поток // необходимо завершить, то будет сгенерировано исключение // ActiveThreadTerminatingSignal и произойдет завершение потока, т.к. // оно не перехватывается внутри цикла. Using use(*this); ... // В этом блоке объект всегда находится не в удаляемом состоянии и // преобразование обычного указателя (например, this) к ссылочному // никогда не приведет к результату NULL. // Выход из блока. use.Unuse(); ... // Код, специфичный для синхрообъектов. // Вход в Using-секцию, в дополнение производится вход в синхропространство. UsingSync suse(*this); ... // Находимся в синхропространстве. Деинициализация произойдет в деструкторе suse. } }
Жизнь объекта - Жизнь потока ----------------- Начало создания объекта. | _ | |<-Запуск потока. | | ----------------- Выход из метода запуска объекта, работа. | | | | | |<-Выполнение потока, когда объект находится в рабочем состоянии (на него есть ссылки). | | | | ----------------- Переход объекта в удаляемое состояние (на него не осталось ссылок), потоку сообщается о завершении. | | | |<-Выполнение потока, когда объект находится в удаляемом состоянии. | | Поток может узнать о завершении статическим методом ActiveThread::Terminated() или конструкцией Using. | | После того как поток узнает о завершении он должен выполнить процедуру завершения. | |<-Завершающие действия потока, объект находится в удаляемом состоянии. | X | ----------------- Вызов деструктора или метода OnReleaseInstance когда запущенных потоков не осталось (для синхрообъектов - | когда будет возможен вход в синхропространство). | | Выполнение деинициализации объекта. X
Замечание по созданию потоков в конструкторе. Создавать потоки в конструкторе активного объекта нельзя, т.к. при создании потока временно создается ссылочный указатель на данный объект. Почему нельзя использовать ссылочные указатели на объект в его конструкторе рассмотрено в разделе "Подсчет ссылок".
Данный класс обеспечивает многопоточность.
См. определение в файле ActiveObject.h строка 169
Открытые типы | |
typedef RefPtr < ActiveObject > | Ptr |
Открытые члены | |
template<typename MethodSignatureT> | |
SpecUtils::ActiveThreadFunctor < typename SignatureInfo < MethodSignatureT > ::FuncSign > | StartThread (MethodSignatureT Method, ActiveThread::ThreadPriority Priority=ActiveThread::tpNormal) |
Запустить поток для данного активного объекта. | |
Защищенные типы | |
typedef Register < SpecUtils::BasicActiveThreadImpl::Ptr > | ThreadsRegister |
Защищенные члены | |
ActiveObject () | |
Конструктор по умолчанию. | |
virtual | ~ActiveObject () |
Деструктор. | |
virtual void | AllThreadsFinished ()=0 |
Служебный виртуальный метод. | |
void | TerminateAllThreads () |
Сообщить всем потокам об останове и перейти в режим ожидания завершения всех потоков объекта. | |
Друзья | |
class | SpecUtils::BasicActiveThreadImpl |
typedef RefPtr<ActiveObject> Cntm::ActiveObject::Ptr |
typedef Register<SpecUtils::BasicActiveThreadImpl::Ptr> Cntm::ActiveObject::ThreadsRegister [protected] |
См. определение в файле ActiveObject.h строка 207
Cntm::ActiveObject::ActiveObject | ( | ) | [inline, protected] |
virtual Cntm::ActiveObject::~ActiveObject | ( | ) | [inline, protected, virtual] |
SpecUtils::ActiveThreadFunctor< typename SignatureInfo < MethodSignatureT >::FuncSign > Cntm::ActiveObject::StartThread | ( | MethodSignatureT | Method, | |
ActiveThread::ThreadPriority | Priority = ActiveThread::tpNormal | |||
) | [inline] |
Запустить поток для данного активного объекта.
После вызова метода StartThread() в скобках указываются аргументы, которые следует передать запускаемому в новом потоке методу. Если аргументов нет, ставятся круглые скобки. Если после вызова метода StartThread() не будет второй пары скобок, то поток запущен не будет. Пример:
StartThread(&Class1::Thread1)(45, "Text"); StartThread(&Class1::Thread2)();
Метод StartThread()() возвращает хэндл созданного потока (см. класс Cntm::ActiveThreadHandle).
Исключение: SystemException - системная ошибка при создании нового потока.
Method | - указатель на метод активного объекта, который будет вызван в новом потоке. | |
Priority | - приоритет создаваемого потока. |
См. определение в файле ActiveObject.h строка 197
Перекрестные ссылки Cntm::ActiveThread::Start().
virtual void Cntm::ActiveObject::AllThreadsFinished | ( | ) | [protected, pure virtual] |
Служебный виртуальный метод.
Вызывается, когда все потоки завершились. В потомках вызывает методы DeleteInstance() классов, реализующих подсчет ссылок.
void Cntm::ActiveObject::TerminateAllThreads | ( | ) | [protected] |
Сообщить всем потокам об останове и перейти в режим ожидания завершения всех потоков объекта.
Служебный метод. Когда все потоки будут завершены, вызовется AllThreadsFinished() для дальнейшей деинициализации.
Данный метод вызывается при переходе объекта в удаляемое состояние из метода DeleteInstance().
В промежутке от вызова TerminateAllThreads() до AllThreadsFinished() (состояние ожидания завершения потоков) объект находится в удаляемом состоянии, поэтому создание новых потоков невозможно.
См. определение в файле ActiveObject.cpp строка 16
Перекрестные ссылки Cntm::Register< ValueT, StoreT >::Enumerator::Current(), Cntm::Register< ValueT, StoreT >::GetEnumerator() и Cntm::Register< ValueT, StoreT >::Enumerator::Next().
friend class SpecUtils::BasicActiveThreadImpl [friend] |
См. определение в файле ActiveObject.h строка 243
© Овсеевич Р.В. Документация по CntmLib 1.1.4 от 28 May 2008. Создано системой 1.5.3 |