Реализация многопоточных кэшей
Базовый класс для кэшированных данных и класс менеджера кэшей определены в файле tool_multithreading.h.
Менеджер кэшей CacheManager
Менеджер кэшей определен как шаблонный класс CacheManager для класса кэшированных данных и содержит члены:
longTerm – данные главного потока; используются при последовательном выполнении и для инициализации данных потоков при параллельном выполнении.
tcache – список кэшей с данными, которые используются при параллельном выполнении. Каждый поток по идентификатору threadKey использует только свою копию данных. Для многопоточной обработки зависимых (имеющих общие данные) объектов должен использоваться режим многопоточных вычислений mtm_Items.
lock – блокировка менеджера кэшей, которая используется при изменении списка кэшей и изменении кэша главного потока.
Шаблонный класс CacheManager<class T> реализует методы:
T * operator() – возвращает указатель на кэш (данные) текущего потока. Всегда возвращает ненулевое значение.
void Reset( bool resetLongTerm ) – аннулирует данные кэшей. Если resetLongTerm == true, также удаляет кэш главного потока.
void CleanAll( bool doPostproc, bool force ) – удаляет все кэши и отписывается от сборки мусора. Должна вызываться в последовательном участке кода.
T * LongTerm() – возвращает указатель на кэш (данные) главного потока. Всегда возвращает ненулевое значение. Все операции с кэшем главного потока должны быть защищены блокировкой кэша.
CommonMutex * GetLock() – возвращает указатель на блокировку для операций с кэшем главного потока с учетом того, исполняется ли код параллельно. Может возвращать нулевое значение (удобно для использования с ScopedLock).
CommonMutex * GetLockHard() – возвращает указатель на блокировку для операций с кэшем главного потока. Всегда возвращает ненулевое значение.
bool ResetCacheData() – функция очистки, используемая сборщиком мусора.
Алгоритм работы менеджера кэшей зависит от режима многопоточности ядра MbeMultithreadedMode.
Если определен режим многопоточных вычислений не ниже mtm_SafeItems, менеджер кэшей инициирует использование выделенных кэшей для каждого потока. При этом менеджер кэшей по идентификатору потока выбирает и выдает потоку его копию данных.
При переходе к последовательной работе менеджер вызывает функцию Postprocess() для пост-обработки кэшей. Указанная функция итерируется по кэшам, использованным при параллельных вычислениях, и вызывает функцию longTerm.MergeWith( AuxiliaryData * ) с данными каждого кэша в качестве параметра. После завершения работы функции Postprocess() многопоточные кэши удаляются. Далее на запрос кэша менеджер кэшей выдает только кэш главного потока (longTerm).
Класс CacheManager является производным от класса CacheCleaner, что позволяет запускать чистку кэшей по требованию.
Базовый класс кэшированных данных AuxiliaryData
Класс кэшированных данных должен наследоваться от базового класса AuxiliaryData и содержать определения конструктора по умолчанию и конструктора копирования.
Кроме того, если требуется пост-обработка кэшей после выхода из параллельных вычислений, наследник класса AuxiliaryData должен переопределить метод void MergeWith( AuxiliaryData * ), который вызывается менеджером кэшей для данных основного потока с данными каждого из многопоточных кэшей в качестве параметра. Реализация MergeWith() по умолчанию не делает никакой пост-обработки.
Класс объекта ядра, использующего кэширование, должен определять кэшированные данные как класс, наследованный от AuxiliaryData, и включать в себя экземпляр CacheManager как член класса.
При многопоточной обработке зависимых (имеющих общие данные) объектов должен использоваться режим многопоточных вычислений не ниже mtm_SafeItems.