Главная arrow С++ (часть 3) arrow Дополнительные переменные-члены

Дополнительные переменные-члены

Многопоточная версия сборщика мусора GCPtr требует включения следую, щих переменных-членов:
// Переменные-члены, поддерживающие многопоточность. unsigned tid; // Идентификатор (id) потока static HANDLE hThrd;    // дескриптор потока static HANDLE hMutex; // дескриптор мьютекса
static int instCount; // счетчик объектов GCPtr
Идентификатор потока, используемый сборщиком мусора, хранится в переменной tid. Она требуется при вызове функции _beginthreadex (). Дескриптор потока содержится в переменной hThrd. Дескриптор мьютекса, необходимого для синхронизации доступа к объекту GCPtr, запоминается в переменной hMutex. Счетчик существующих объектов типа GCPtr хранится в переменной instcount. Последние три переменные описаны как статические (static), так как они используются всеми экземплярами GCPtr. Далее приведен фрагмент задания их значений вне тела класса GCPtr. template <class Т, int size>
int GCPtr<T, size>::instCount = 0;
template <class T, int size>
HANDLE GCPtr<T, size>::hMutex = 0;
template <class T, int size>
HANDLE GCPtr<T, size>::hThrd = 0;
Многопоточный конструктор объекта GCPtr
Помимо своих первоначальных обязанностей многопоточный конструктор GCPtr о должен создавать мьютекс, запускать поток для сбора мусора и обновлять счетчик экземляров. Далее приведена его новая версия.
// Создает как инициализированные, так и неинициализированные объекты. GCPtr(Т *t=NULL)  {
// Когда создается первый объект, создает также мьютекс // и регистрирует функцию shutdown(). if(hMutex==0)  {
hMutex = CreateMutex(NULL, 0, NULL);
atexit(shutdown);
}
if (WaitForSingleObject(hMutex, 10000)==WAIT_TIMEOUT) throw TimeOutExc();
list<GCInfo<T> >::iterator p;
p = findPtrInfo(t);
// Если элемент есть в списке gclist,
// увеличивает его счетчик ссылок на единицу.
// В противном случае добавляет этот элемент в список.
if(p != gclist.end())
p->refcount++; // наращивает счетчик ссылок else {
// Создает и запоминает этот элемент. GCInfo<T> gcObj(t, size); gclist.push_front(gcObj);
}
addr = t;
arraySize = size;
if (size > 0) isArray = true;
else isArray = false;
// Наращивает счетчик экземпляров при создании
// каждого нового объекта.
instCount++;
// Если поток для сбора мусора //не выполняется, запускает его. if(hThrd==0)  {
hThrd = (HANDLE) _beginthreadex(NULL, 0, gc, (void *) 0, 0,  (unsigned *) &tid);
// Для некоторых приложений лучше понизить приоритет
// сборщика мусора, как показано далее:
//
// SetThreadPriority(hThrd,
// THREAD_PRIORITY_BELOW_NORMAL);
ReleaseMutex(hMutex);
}
Давайте внимательно проанализаруем код. Если переменная hMutex равна О, следовательно, создается первый объект GCPtr, и нет еще ни одного созданного для сбора мусора мьютекса. В этом случае создается мьютекс, и его дескриптор присваивается переменной hMutex. В это же время с помощью вызова функции atexit о регистрируется функция shutdown*), как функция завершения.
Обратите особое внимание на то, что в многопоточном сборщике мусора функция shutdown () служит двум целям. Во-первых, как и в первоначальной версии, она освобождает любую неиспользуемую память, не очищенную из-за наличия циклической ссылки. Во-вторых, когда программа, использующая многопоточный сборщик мусора, завершается, она останавливает выполнение потока сбора мусора. Это означает, что к этому моменту могут еще оставаться неудаленные, динамически размещенные объекты. Это важно, так как у них могут быть деструкторы, которые должны быть вызваны. Поскольку функция shutdown () удаляет все оставшиеся объекты, она уничтожит и их.
Далее запрашивается МЬЮТекС С ПОМОЩЬЮ функции WaitForSingleObject о.
Ее вызов препятствует одновременному обращению двух потоков к списку gclist. Как только получен мьютекс, выполняется поиск в списке gclist элемента с адресом, соответствующим значению переменной t. Если такой элемент найден, его счетчик ссылок увеличивается на единицу. Если же элемента с адресом, заданным в t, нет, создается новый объект типа Gcmf о, содержащий этот адрес, и добавляется в список gclist. Затем счетчик instcount наращивается с помощью операции инкремента. Напоминаю, что instcount инициализируется с нулевым значением. Увеличиваясь на единицу при каждом создании объекта, он позволяет следить за числом существующих объектов. Сборщик мусора будет выполняться до тех пор, пока счетчик экземпляров больше 0.
Далее, если дескриптор потока hThrd равен 0 (как при инициализации), следовательно, нет ни одного потока, созданного для сборщика мусора-В этом случае вызывается функция _beginthreadex () для запуска потока-Дескриптор этого потока присваивается переменной hThrd. Вызывается функция потока дс (), которая кратко обсуждается далее. В заключение, освобождается мьютекс и конструктор возвращается в вызывающую программу. Важно отметить, что каждый вызов функции WaitForSingleObject о должен быть сбалансирован вызовом функции ReleaseMutexO, как это сделано в конструкторе объекта GCPtr. Сбой при освобождении мьютекса может создать тупиковую ситуацию.
исключение TimeOutExc
KJIIC вы, вероятно, заметили, в коде конструктора GCPtrO, описанного в предыдущем разделе, если мьютекс не может быть получен по истечении 10 с, генерируется исключение TimeOutExc. По правде сказать, Юс— это слишком долго, и в этом случае превышения времени ожидания никогда не произойдет, если только что-нибудь не разрушит планировщик заданий операционной системы. Однако если такое событие все-таки возникнет, в коде вашего приложения можно предусмотреть обработку этого исключения. Описание класса TimeOutExc приведено далее. // Генерируется исключение при превышении времени ожидания // исключительного права доступа к hMutex. //
class TimeOutExc { // Добавьте обработку, необходимую вашему приложению.
};
Обратите внимание, что этот класс не содержит членов. Его присутствия, как уникального типа данных, достаточно для целей, преследуемых в этой главе. Конечно, вы можете добавить собственную обработку, если захотите.
 
общепит калькуляция, Оформление, темы для nokia 5530 .