|
Программирование >> Формирование пользовательского контейнера
126 Глава я 11 Уменьшает на единицу счетчик экземпляров при каждом уничтожении объекта. Instcount-; ReieaseMutex(hMutex); Функция дс{) Код функции потока для сборщика мусора, названной дс (), приведен далее. Точка входа для потока сборщика мусора, tenplate <class Т, int size> unsigned stdcall GCPtr<T, size>::gc(void * param) ( #ifdef DISPLAY cout Garbage collection started.\n ; #endif whiledsRunningO) { collect(); collectO; собирает мусор перед выходом из функции Освобождает и устанавливает дескриптор потока таким образом, чтобы поток сбора, мусора можно было возобновить при необходимости. CloseHandle(hThrd); hThrd = 0; #ifdef DISPLAY cout Garbage collection terminated for typeid(T) .nameO \n ; #endif return 0; Функция gco очень проста: она выполняется, пока идет сбор мусора-Функция isRunningO возвращает true, если instcount больше О (т. е. есть п<угребность в сборе мусора), и false - в противном случае. Внутри цикла непрерывно вызывается функция collectO. Этот подход годится для де-щонстрации многопоточного сборщика мусора, но вероятно слишком неэффективен для практического применения. Вы можете поэкспериментиро-ь, вызывая функцию collect о реже, например, только если доступная динамическая память почти иссякла. Можно также попробовать вызывать VVindows API-функцию sleep о после каждого вызова функции collect о. функция Sleep о Приостанавливает выполняющийся поток на заданное количество мс. Приостановленный таким образом поток не расходует время процессора. Когда функция isRunningO возвращает false, цикл завершается, вызывая, в конечном счете, завершение функции gc (), которое останавливает поток сбора мусора. Из-за многопоточности возможно наличие неудаленного элемента в списке gclist, даже когда функция isRunningO возврашает false. Для обработки подобной ситуации выполняется завершающий вызов функции collect () перед окончанием функции gc {). В заключение, освобождается дескриптор потока с помощью вызова Windows API-функции CloseHandle () И задания для него нулевого значения. Присваивание О переменной hThrd позволяет конструктору GCPtr повторно запустить поток, если позднее в профамме будут созданы новые объекты типа GCPtr. Функция isRunningO Далее приведен код функции isRunning (). Возвращает true, если сборщик выполняется, static bool isRunningO { return instCount > 0; } Она просто сравнивает значение instCount с 0. Пока переменная instCount больше О, по крайней мере, один указатель типа GCPtr существует и, следовательно, все еще необходим сбор мусора. Синхронизация доступа к списку gciist Многие функции класса GCPtr обращаются к переменной gclist, которая содержит информационный список сбора мусора. Доступ к ней необходимо синхронизировать для того, чтобы исключить попытки двух или нескольких Потоков одновременно использовать gclist. Причину этого легко понять. Если доступ не синхронизировать, то, например, один поток может полу-Ить итератор, указывающий на конец списка, и в это же время другой поток Лобавит или удалит элемент списка. В этом случае итератор станет невер-**Ь1м. Во избежание подобных проблем любой фрагмент кода, обращающийся к списку gclist, должен быть защищен мьютексом. Копирующий конст- руктор, код которого приведен далее, - один из примеров синхронизаци доступа. Копирующий конструктор. GCPtr(const GCPtr &ob) { if(WaitForSingleObject(hMutex, 10000)==WAIT TIMEOUT) throw TimeOutExc(); list<GCInfo<T> >::iterator p; p = findPtrInfo{ob.addr); p->refcount++; increment ref count addr = ob.addr; arraySize = ob.arraySize; if(arraySize > 0) isArray = true; else isArray = false; instCount++; увеличивает счетчик экземпляров с учетом копии ReieaseMutex(hMutex); Обратите внимание на то, что копирующий конструктор начинает с запроса мьютекса. Затем он создает копию объекта и увеличивает счетчик ссылок для фрагмента памяти, на которую указывает созданный объект. На выходе копирующий конструктор освобождает мьютекс. Этот базовый метод применяется во всех функциях, обращающихся к списку gclist. Два дополнительных изменения Есть еще два изменения, которые мы должны сделать в первоначальной версии сборщика мусора. Во-первых, напоминаю, что в первоначальной версии объявлена статическая переменная first для индикации момента создания первого объекта GCPtr. Теперь эта переменная не нужна, ее роль исполнит переменная hMutex. Следовательно, удалите из класса GCPtr переменную first. Поскольку это статическая переменная, вы должны также удалить ее определение, размещенное вне тела класса GCPtr. В первоначальной однопоточной версии сборщика мусора вы могли наблюдать за сбором мусора, если определили макрос display. Большая часть его кода удалена в многопоточной версии, так как многопоточность делает вывод программы беспорядочным и в большинстве случаев непонятным-В многопоточной версии определение макроса display позволяет вам просто узнать, когда запускается сборшик мусора и когда он завершает работу.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |