Последовательное копирование
Функция Swap() вызывается в произвольные моменты и, скорее всего, будет работать в течение некоторого времени. В работе программы возникают непредсказуемые затяжки, а это бесит пользователей едва ли не больше, чем аппаратные сбои. К счастью, алгоритм Бейкера легко модифицировать, чтобы копирование выполнялось поэтапно в фоновом режиме.
На мосту Бей-Бридж в Сан-Франциско постоянно работает бригада маляров. Она начинает красить мост с одного конца и через пару лет успешно докрашивает до другого. К этому времени можно начинать красить заново, в другую сторону. Работа идет постоянно, не считая редких перерывов из-за землетрясений или демонстраций протеста. В сущности, именно так алгоритм Бейкера превращается в схему последовательного уплотнения.
Начинаем следующий заход на класс Space. Функция Swap() делится на две части, одна из которых переключает активные половины, а другая многократно вызывается и при каждом вызове копирует по одному объекту.
class Space {
private:
VoidPtrIterator* iterator; // Информация о копировании
HalfSpace A, B;
HalfSpace* active;
HalfSpace* inactive;
void Swap(); // Переключить активную половину, скопировать объекты
public:
Space() : active(&A), inactive(&B), iterator(NULL) { Swap(); }
void* Allocate(size_t size);
void Copy1();
};
void* Space::Allocate(size_t size)
{
void* space = active->Allocate(size);
if (space != NULL)
// Исключение - нехватка памяти
return space;
}
void Space::Swap()
{
if (active == &A)
{
active = &B;
inactive = &A;
}
else
{
active = &A;
inactive = &B;
}
active->Reinitialize();
delete iterator;
iterator = VoidPtr::pool->iterator();
}
void Space::Copy1()
{
if (!iterator->More())
Swap(); // Начать работу в другую сторону
else
{
VoidPtr* vp = iterator->Next();
if (vp->address >= inactive &&
vp->address < inactive + sizeof(*inactive))
{
void* new_space = active->Allocate(size);
if (new_space == NULL)
throw(OutOfMemory());
memcpy(new_space, vp->address, vp->size);
vp->address = new_space;
}
}
}
Функцию Copy1() необходимо вызывать как можно чаще, однако делать это можно в ходе
нормальной работы программы. Новые объекты размещаются в активной половине, смешиваются со скопированными объектами, но это не приносит вреда. Поскольку перед копированием мы убеждаемся, что объект в данный момент находится в неактивном пространстве, созданные в активной половине объекты остаются без изменений.