Библиотека CntmLib C++  :: Синхронизация (пакет Cntm.Synchro)
Документация
  • Знакомство с CntmLib
  • Общие сведения
  • Установка и использование
  • Основные пакеты
  • Вспомогательные пакеты
  • Лицензия
  • Описание классов
  • НАЗНАЧЕНИЕ ПАКЕТА

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

     

    СИНХРОПРОСТРАНСТВА

    Понятие синхропространства

    Пакет предоставляет механизм, обеспечивающий синхронизацию потоков и выполнение отложенных (сериализованных) операций. Этот механизм называется синхропространством.

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

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

    В программе м.б. несколько синхропространств. Синхропространству соответствует класс Cntm::SynchroSpace. Более детальное описание функций синхропространства приведено в документации по классу Cntm::SynchroSpace.

    Типы синхропространств

    Синхропространства делятся на 2 типа: главные и дополнительные. В программе м.б. только одно главновное синхропространство и несколько дополнительных.

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

    Главные синхропространства могут сами полностью реализовывать свои функции либо интегрироваться с другими библиотеками, предоставляющими подобную функциональность (на данный момент реализована интеграция с библиотекой QT). Главному синхропространству, которое само реализует все функции, соответствует класс Cntm::MainSynchroSpace. Для интеграции с QT следует использовать класс Cntm::QTMainSynchroSpace. Интеграция заключается в том, что для синхронизации используется мьютекс библиотеки QT, а для выполнения отложенных операций - цикл обработки событий QT, т.е. отложенные операции синхронизированы со всеми событиями QT.

    Дополнительные синхропространства не несут специальных функций. Дополнительному синхропространству соответствует класс Cntm::ExtraSynchroSpace.

     

    СИНХРООБЪЕКТЫ

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

    Синхрообъект является ссылочным объектом. Чтобы определить свой класс синхрообъекта его нужно унаследовать от одного из 3 классов: Cntm::SynchroRefBase, Cntm::SynchroRefBaseEx и Cntm::SynchroAggregatedBase. Эти классы объединяют соответствующий способ подсчета ссылок и средства синхронизации, предоставляемые Cntm::SynchroObject. Особенностью классов Cntm::SynchroRefBase и Cntm::SynchroRefBaseEx является то, что гарантируется отложенный вызов их деструкторов и метода OnReleaseInstance() для Cntm::SynchroRefBaseEx.

     

    ОСОБЕННОСТИ ИСПОЛЬЗОВАНИЯ

    Точки входа и выхода из синхропространства задаются вызовами методов Enter() и Leave() соответственно. Существует альтернативный способ входа и выхода - с помощью scoped-объектов. В конструкторе scoped-объекта происходит вход, а в деструкторе - выход. Классы, реализующие эту функциональность - Cntm::Sync и Cntm::ReentrantSync.

    Отложенные операции (точнее, отложенные синхрозадачи) редко используются напрямую, обычно применяются средства, основанные на отложенных операциях. К этим средствам относятся отложенные события и отложенные асинхронные процедуры. Также отложенные операции используются и при уничтожении самих синхрообъектов.

     

    ПРИМЕР ИСПОЛЬЗОВАНИЯ

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

    Класс синхрообъекта

    /**
     * Пример класса синхрообъекта, выполняющий операции взаимодействия с 
     * объектами пользовательского интерфейса из другого потока.
     * Примечание: QT рекомендует, чтобы операции с объектами QT производились
     * из главного потока, в котором запущен цикл обработки событий.
     */
    class Class1: public SynchroRefBase
    {
    public:
        typedef RefPtr<Class1> Ptr;
    
        /**
         * Запускает поток для выполнения каких-либо действий.
         */
        void Start(Form1* form, string text1, string text2)
        {
            // Сбрасываем флаг останова перед запуском потока.
            finish = false;
            
            // Запускаем метод MyThread в другом потоке. Ему можно передавать 
            // любые аргументы. Набор аргументов должен соответствовать сигнатуре
            // указанного метода. Особенность подобного запуска в том, что объект
            // не может быть уничтожен во время выполнения потокового метода, 
            // даже если не осталось ни одного ссылочного указателя на него.
            ThreadProc(&Class1::MyThread)(form, text1, text2);
        }
        
        /**
         * Останавливает поток.
         */
        void Stop()
        {
            finish = true;
        }
    
    private:
        bool finish;
        
        /**
         * Потоковый метод. Запускается из метода Start().
         */
        void MyThread(Form1* form, string text1, string text2)
        {
            // Входим в главное синхропространство QT (т.к. мы используем механизмы
            // интеграции синхропространства со средствами QT, то тут используется
            // мьютекс библиотеки QT, доступный через методы QApplication::lock(),
            // QApplication::tryLock() и QApplication::leave()) и синхронизированно
            // с прочими операциями и событиями QT считываем текст заголовка окна.
            Sync s(this); // Входим в главное синхропространство.
            string caption = form->caption();
            s.Leave(); // Досрочно выходим из синхропространства, не дожидаясь деструктора s.
            
            // Устанавливаем новый заголовок. Для этого мы применим отложенный
            // вызов метода установки заголовка окна. Это значит, что метод будет
            // вызван в контексте главного потока, т.е. синхронизированно со
            // всей библиотекой QT, что является обязательным условием стабильной
            // работы. По отношению к потоку этот вызов будет асинхронным, т.е.
            // поток не будет ждать завершения установки заголовка окна.
            AsyncProc::Defer(form, &Form1::setCaption)(caption + text1);
            
            // В цикле до начала завершения работы системы выполняем какие-то
            // операции, например, пишем в консоль.
            while (!finish)
            {
                cout << "Thread work" << endl;
                sleep(1);
            }
            
            // Напоследок отображаем диалоговое окно, содержащее text2. Поток
            // завершится, не дожидаясь, когда диалог будет закрыт, т.е. вызов
            // асинхронный по отношению к потоку. Однако сам объект может быть
            // уничтожен не раньше, чем завершится метод ShowMsgBox.
            Defer(&Class1::ShowMsgBox)(text2);
        }
        
        /**
         * Процедура отображения диалогового окна, которое произойдет в основном.
         * потоке, как того требует библиотека QT.
         */
        void ShowMsgBox(string text)
        {
            QMessageBox::information(NULL, "Information", text, QMessageBox::Ok);
        }
    };

    Использование синхрообъекта

    int main(int argc, char **argv)
    {
        // Создание объекта приложения QT и главного синхропространства, 
        // интегрированного с библиотекой QT. Примечание: класс
        // QTMainSynchroSpace::Application наследует QApplication.
        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", "Thread finished");
        
        // Запускаем приложение.
        int res = app.exec();
        
        // После завершения приложения (например, закрыто главное окно)
        // останавливаем работу объекта, на который указывает ptr.
        ptr->Stop();
        
        // Перед выходом из функции main происходит следующее:
        // 1. Срабатывает деструктор ptr, уничтожая последнюю и единственную явную
        // ссылку на объект, но т.к. поток в методе Class1::MyThread() и метод отображения
        // диалога Class1::ShowMsgBox() незавершены, то имеются неявные ссылки на объект.
        // 2. В деструкторе объекта приложения app происходит ожидание
        // уничтожения всех синхрообъектов. Объект класса Class1 не будет удален, пока не
        // завершится метод Class1::ShowMsgBox(), т.е. не будет закрыт диалог. Т.о. выход 
        // из программы произойдет только тогда, когда отработает деструктор синхрообъекта.
        return res;
    }

     

    СМ.

  • Базовый класс синхропространства Cntm::SynchroSpace
  • Конкретные классы синхропространств Cntm::MainSynchroSpace, Cntm::QTMainSynchroSpace, Cntm::ExtraSynchroSpace
  • Основа классов синхрообъектов Cntm::SynchroObject
  • Базовые классы синхрообъектов Cntm::SynchroRefBase, Cntm::SynchroRefBaseEx, Cntm::SynchroAggregatedBase
  • Классы scoped-объектов для входа в синхропространство Cntm::Sync, Cntm::ReentrantSync
  • Пример использования QTSyncSpaceExp.cpp

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

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