Библиотека CntmLib C++  :: Знакомство с CntmLib
Документация
  • Знакомство с CntmLib
  • Общие сведения
  • Установка и использование
  • Основные пакеты
  • Вспомогательные пакеты
  • Лицензия
  • Описание классов
  • ВВЕДЕНИЕ

    Раздел содержит краткий и упрощенный обзор возможностей, предоставляемых библиотекой. Обзор построен, в основном, на рассмотрении примеров типичного использования средств библиотеки.

    Для того, чтобы понять приведенные ниже примеры желательно иметь представление о шаблонах языка C++, т.к. почти все механизмы библиотеки построены на них, иметь общее понятие о подсчете ссылок, событиях (или сигналах и слотах), потоках выполнения, синхронизации потоков и асинхронных операциях. В примерах часто встречаются средства библиотеки QT, поэтому желательно иметь сведения о работе с библиотекой в части использования объекта приложения и организации цикла обработки событий, а также поддержки потоков выполнения библиотекой QT.

     

    ПОДСЧЕТ ССЫЛОК

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

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

    В общем случае механизм подсчета ссылок состоит из 2 частей - базового класса, реализующего подсчет ссылок и умного указателя, который похож на обычный, но, кроме всего прочего, автоматизирует управление подсчетом ссылок на объект. Наиболее простым базовым классом для подсчета ссылок является RefBase, класс умного указателя, осуществляющего увеличение и уменьшения кол-ва (в библиотеке такие указатели называются ссылочными), представлен шаблонным классом RefPtr<T>.

    В нижеприведенном примере объявляется класс объекта с подсчетом ссылок и создается экземпляры этого класса.

    class ClassName: public RefBase 
    {
    public:
    typedef RefPtr<ClassName> Ptr;
    int Result;
    ClassName(): Result(1) { cout << "Объект создан" << endl; }
    ~ClassName() { cout << "Объект уничтожен" << endl; }
    void Exec() { Result = 0; cout << "Операция выполнена" << endl; }
    };

    int func(ClassName::Ptr p)
    {
    p->Exec();
    return p->Result;
    }

    int main()
    {
    ClassName::Ptr ptr(new ClassName); // Создание объекта и инициализация указателя.
    return func(ptr); // Перед выходом из main() ptr будет уничтожен, что приведет к
    // обнулению ссылок на объект класса ClassName и его уничтожению.
    }

    Вывод на консоль:
    > Объект создан
    > Операция выполнена
    > Объект уничтожен

     

    СОБЫТИЯ

    События - это способ для сервера оповещать клиентов об изменении своего состояния. При этом клиентов м.б. несколько и сервер ничего не знает о клиентах, он только предоставляет возможность клиенту подключиться для обработки событий.

    В простейшем случае в качестве события выступает объект класса DirectEvent<SignatureT>. В качестве параметра шаблона выступает сигнатура обработчика, т.е. перечень типов аргументов, которые будут переданы обработчику при генерации события. В качестве обработчика выступает один из методов объекта-клиента. Обязательное условие, которое проверяется во время компиляции, - сигнатура метода должна соответствовать сигнатуре события. Подключение обработчика к событию производится специальным объектом связи - EventLink. Пока объект существует, обработчик подключен, когда объект связи разрушается, происходит отключение обработчика от события.

    В примере создается объект сервера и несколько объектов клиентов, обрабатывающих его событие.

    class Server
    {
    public:
        // Обявление объекта события. Оно включает в себя сигнатуру обработчика.
        DirectEvent<void(string, date)> ActionEvent;
        
        // Метод, генерирующий событие.
        void Action(string text)
        {
            // Конструкция ActionEvent(...) производит вызов обработчиков и 
            // передает им указанные при генерации аргументы.
            ActionEvent(text, date(day_clock::local_day()));
        }
    };
    
    class Client
    {
    public:
        // Конструктор производит инициализацию связи между объектом события
        // server.ActionEvent и обработчиком, который задается указателем на объект
        // и метод обработчика - this, &Client::OnAction.
        Client(int ix, const Server& server):
            index(ix), onAction(server.ActionEvent, this, &Client::OnAction) {}
    
    private:
        int index;
        
        // Объект связи события и обработчика. Когда клиент уничтожается, уничтожается
        // и объект связи, при этом происходит отключение обработчика от события сервера.
        EventLink onAction;
        
        // Метод обработчик события. Вызывается при генерации события сервером. Значения
        // его аргументов - те, что были установлены при генерации события сервером.
        void OnAction(string text, date dt) { cout << index << ": " << text << dt << endl; }
    };
    
    void main()
    {
        Server server;
        {
            Client client1(1, server);
            Client client2(2, server);
            Client client3(3, server);
            server.Action("Execute action ");
        }
        server.Action("No execute action ");
    }
    
    Вывод на консоль:
    > 1: Execute action 14.10.05
    > 2: Execute action 14.10.05
    > 3: Execute action 14.10.05	

    Кроме простых событий, которые рассмотрены в примере, имеются отложенные события, которые рассмотрены в разделе документации, описывающем события.

     

    СОЗДАНИЕ ПОТОКОВ

    Поток в библиотеке CntmLib - это метод объекта, который начинает выполняться параллельно с методом или функцией, запустившем его. Потоки в библиотеке являются частным случаем асинхронных процедур, которые рассмотрены в соответствующем разделе документации. Механизм запуска нового потока довольно прост и позволяет передавать потоковому методу аргументы произвольных типов.

    В нижеприведенном примере создается поток, которому передается три аргумента - 2 строки и число.

    class Class1
    {
    public:
        Class1()
        {
            // Создание и запуск потока с передачей ему 3 аргументов - 2 строки и числа.
            AsyncProc::Thread(this, &Class1::ThreadMethod)("Start", "Finis", 5);
        }
        
        void ThreadMethod(string text1, string text2, int delay)
        {
            cout << text1 << ". sleep " << delay  << "sec... ";
            sleep(delay);
            cout << text2;
        }
    };

     

    СИНХРОНИЗАЦИЯ

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

    // Создаем класс, обладающий встроенными средствами синхронизации. Этот класс
    // запускает новый поток и выполняет в нем операции с объектами QT.
    class Class1: public SynchroRefBase
    {
    public:
        typedef RefPtr<Class1> Ptr; // Обявляем ссылочный указатель для удобства использования.
    
        // Метод, в котором происходит запуск потока.
        void Start(Form1* form, string text)
        {
            // Запускаем поток, который выполнит метод MyThread().
            ThreadProc(&Class1::MyThread)(form, text);
        }
    
    private:
    
        // Потоковый метод. Запускается из метода Start().
        void MyThread(Form1* form, string text)
        {
            // Так можно синхронизироваться с QT. Синхронизировавшись,
            // считываем заголовок окна.
            Sync s(this);
            string caption = form->caption();
            s.Leave();
            
            // Так можно вызвать произвольный метод произвольного объекта в контексте
            // главного потока. Производим установку нового заголовка из главного потока.
            AsyncProc::Defer(form, &Form1::setCaption)(caption + text);
        }
    };
    
    int main(int argc, char **argv)
    {
        // Создание специального объекта приложения QT, который обеспечивает 
        // интеграцию CntmLib с библиотекой QT.
        QTMainSynchroSpace::Application app(argc, argv);
        
        // Создание главного окна.
        Form1* form = new Form1();
        form->setCaption("Form1");
        form->show();
        app.connect( &app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()) );
        
        // Создание объекта и запуск его работы.
        Class1::Ptr ptr(new Class1);
        ptr->Start(" - thread started");
        
        //Запускаем приложение.
        return app.exec();
    }

     

    ЧТО ДАЛЬШЕ?

    После рассмотрения примеров их можно откомпилировать. Для этого нужно скачать и установить библиотеку CntmLib.

    Далее нужно создать исходный файл, содержащий текст примера, а также необходимые директивы:

    #include <string>
    #include <iostream>
    #include <Cntm/RefCount.h>
    #include <Cntm/Events.h>
    #include <Cntm/AsyncProc.h>
    #include <Cntm/Synchro.h>
    
    using namespace std;
    using namespace Cntm;

    Для примера синхронизации необходимо определить класс главного окна - Form1. Это можно сделать с помощью QT Designer.

    Для ознакомления со всеми возможностями библиотеки CntmLib читайте документацию.


    Главная :: Документация :: Описание классов :: Download 

    © 2005, Овсеевич Р.В.
    SourceForge.net Logo