Анимация
JavaScript
|
Главная Библионтека тельным, предупреждая возможные исключительные ситуации и преждевременные выходы из функций. Для решения этой проблемы во многих прикладных интерфейсах языка С++ определяется объект Lock, который инициализируется мьютексом. Конструктор объекта Lock вызывает функцию Acqui ге, а его деструктор - функцию Release. Таким образом, размещая объект Lock в стеке, можно гарантировать правильное чередование вызовов функций Acqui ге и Release даже в исключительных ситуациях. Для обеспечения машинной независимости в библиотеке Loki сами мьютексы не определяются. Предполагается, что вы уже используете собственную библиотеку для поддержки многопоточного режима, в которой определены свои мьютексы. Было бы глупо дублировать их функциональные возможности. Вместо этого с помощью мьютексов в библиотеке Loki реализуется высокоуровневая семантика блокировки. П.5. Семантика блокировки в объектно-ориентированном программировании Объекты синхронизации связаны с совместно используемыми ресурсами. В объектно-ориентированном профаммировании ресурсами являются объекты. Таким образом, в объектно-ориентированной профамме объект синхронизации связан с объектами приложения. Следовательно, каждый совместно используемый объект должен содержать объект синхронизации и блокировать его в каждой модифицирующей функции-члене, как это сделано в примере с классом BankAccount. Сфуктура, в которой каждому совместно используемому объекту соответствует свой объект синхронизации, известна под названием блокировки на уровне объектов (object-level locking). Однако иногда хранить отдельный мьютекс для каждого объекта накладно. В этом случае следует применять стратегию, основанную на использовании только одного мьютекса для отдельного класса. Рассмофим для примера класс String. Время от времени возникает необходимость блбкировать его объекты. Однако мы не хотим хранить отдельный мьютекс для каждого объекта этого класса. Это привело бы к увеличению размеров объектов, и копировать их стало бы неудобно. В этом случае для всех объектов класса String можно использовать один статический мьютекс. Как только какой-либо объект класса String выполняет операцию захвата мьютекса, она блокируется во всех остальных объектах этого класса. Эта сфатегия нзывается блокировкой на уровне класса (class-level locking). В библиотеке Loki определены две реализации сфатегий ThreadingModel: классы classLevelLockable и objectLevelLockable. Они инкапсулируют семантику блокировки на уровне объектов и на уровне класса соответственно. template <typename Host> class Class LevelLockable { public: class Lock { public: LockC); LockCHost& obj); template <typename Host> class objectLevelLockable { public: class Lock { public: LockCHostA obj); С технической точки зрения объект класса Lock оставляет мьютекс захваченным. Разница между этими двумя реализациями заключается в том, что объект класса ObjectLevel Lockabl е<т>:: Lock нельзя создать, не передав ему объект класса т, поскольку в классе ObjectLevel Lockable используется стратегия захвата на уровне объектов. Объект вложенного класса Lock захватывает объект (или целый класс), связанный с мьютексом, на все время своего существования. В приложениях реализации стратегии ThreadingModel играют роль базовых классов. Механизм наследования позволяет использовать внутренний класс Lock непосредственно. class MyClass : public ClassLevelLockable <MyClass> { Точный вид стратегии захвата зависит от реализации стратегии ThreadingModel, выбранной в качестве базового класса. Доступные реализации приведены в табл. П.1. Таблица П.1. Реализации стратегии ThreadingModel Шаблонный класс Семантика SingleThreaded Стратегия поддержки многопоточности не применяется совсем. Классы Lock и ReadLock представляют собой пустые макеты ObjectLevel Lockable Семантика блокировки на уровне объектов. Каждому объекту соответствует свой мьютекс. Внутренний класс Lock захватывает мьютекс (и, неявно, связанный с ним объект) ClassLevel Lockable Семантика блокировки на уровне класса. Каждому классу соответствует свой мьютекс. Внутренний класс Lock захватывает мьютекс (и, неявно, все объекты связанного с ним типа) Как показано в следующем примере, синхронизированные функции-члены реализуются очень легко. class BankAccount : public 0bjectLevelLockable<BankAccount> { public: void DepositCdouble amount, const char* user) { Lock lockC*this); ... кладем деньги на счет... mtx .Releasee); void withdrawCdouble amount, const char* user) { Lock 1ockC*this); ... снимаем деньги со счета ... Проблем, связанных с исключительными ситуациями и преждевременным выходом из функций, больше не сушествует. Правильное чередование операций захвата и освобождения гарантируется инвариантами языка. Универсальный интерфейс, обеспечиваемый фиктивным интерфейсом Singleln-heritance, гарантирует синтаксическую корректность. Можно написать код, используюший многопоточный режим, а затем изменять проектные решения, просто меняя потоковую модель. Стратегия ThreadingModel используется в главе 4, Размещение в памяти небольших объектов, главе 5, Обобщенные функторы, и главе 6, Реализация класса Singleton. П.6. Модификатор volatile в языке С-и- предусмотрен модификатор типа volatile, с помошью которого любую переменную можно предоставить в распоряжение нескольких потоков. Однако в однопоточной модели этот модификатор лучше не использовать, поскольку он не позволяет компилятору выполнять некоторые важные виды оптимизации. По этой причине в классе Loki определен внутренний класс volatileType. Внутри класса SomeThreadingMode1<widget> класс volatileType вычисляет объект типа volatile widget для классов class Level Lockable и ObjectLevel Lockable, a также простой объект класса widget для класса SingleThreaded. Пример его использования был описан в главе 6. П.7. Семафоры, события и другие полезные вещи На этом мы завершаем обсуждение средств поддержки многопоточности в библиотеке Loki. Обычные многопоточные библиотеки предоставляют профаммистам намного более разнообразные наборы объектов синхронизации и функций, например, семафоры, события и барьеры памяти (memory barriers). Кроме того, в библиотеке Loki нет функций, акги-вируюших новый поток. Это еше раз подтверждает тот факт, что библиотека Loki обеспечивает безопасное выполнение потоков, но не использует сами потоки. Возможно, в будуших версиях этой библиотеки будет реализована полная потоковая модель. Многопоточность - это область, в которой обобшенное программирование проявляет всю свою мошь. Однако в ней сильно развита конкуренция - в качестве прекрасной машинно-независимой библиотеки для поддержки многопоточного режима можете применять среду АСЕ (Adaptive Communication Environment - адаптивная среда для обмена информацией) (Schmidt, 2000). П.8. Резюме в стандарте языка С-и- потоков нет. Однако вопросы, связанные с синхронизацией многопоточных профамм, значительно влияют на разработку приложений и библиотек. Разные операционные системы поддерживают разные потоковые модели. По 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 [ 102 ] 103 104 105 |