Документация
Знакомство с 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
|