Я столкнулся с досадной проблемой, и мне понадобится совет ...
Допустим, у меня есть несколько маленьких объектов MyObject, которые могут создавать большие объекты MyExtendedObject.MyExtendedObject имеют большой размер и потребляют ресурсы ЦП, поэтому создание выполняется лениво, и я стараюсь как можно скорее удалить их из памяти:
MyExtendedObject * MyObject::GetExtentedObject(){
if(NULL == ext_obj_){
ext_obj_ = new MyExtendedObject;
}
++ref_;
return ext_obj_;
}
void MyObject::ReleaseExtentedObject(){
if(0 == (--ref_))
{
if(NULL != ext_obj_)
{
delete ext_obj_;
ext_obj_ = NULL;
}
}
}
Расширенные объекты создаются только один раз в начале и уничтожаются при выходе из последней вызывающей программы.их.Обратите внимание, что некоторые могут быть созданы несколько раз, но это не проблема.
Теперь это абсолютно не поточно-ориентированный, поэтому я сделал "наивную" потоко-безопасную реализацию:
MyExtendedObject * MyObject::GetExtentedObject(){
Lock();
if(NULL == ext_obj_){
ext_obj_ = new MyExtendedObject;
}
++ref_;
Unlock();
return ext_obj_;
}
void MyObject::ReleaseExtentedObject(){
Lock();
if(0 == (--ref_))
{
if(NULL != ext_obj_)
{
delete ext_obj_;
ext_obj_ = NULL;
}
}
Unlock();
}
Это лучше, но сейчас я трачу некоторое не пренебрежимое количество времени на блокировку и разблокировку ...
У меня было ощущение, что мы можем заплатить блокировку / разблокировку только при создании или разрушении.
Я придумал это решение:
MyExtendedObject * MyObject::GetExtentedObject(){
long addref = InterlockedCompareExchange(&ref_, 0, 0);
long result;
do{
result = addref + 2;
} while ((result-2) != (addref = InterlockedCompareExchange(&ref_, result, addref)));
if(0 == (result&1)){
Lock();
if(NULL == ext_obj_){
ext_obj_ = new MyExtendedObject;
InterlockedIncrement(&ref_);
}
Unlock();
}
return ext_obj_;
}
void MyObject::ReleaseExtentedObject(){
long release = InterlockedCompareExchange(&ref_, 0, 0);
long result = 0;
do{
result = release - 2;
} while ((result+2) != (release = InterlockedCompareExchange(&ref_, result, release)));
if(1 == result)
{
Lock();
if(1 == InterlockedCompareExchange((long*)&ref_, 0, 1))
{
if(NULL != ext_obj_)
{
delete ext_obj_;
ext_obj_ = NULL;
}
}
Unlock();
}
}
Некоторые объяснения:
Я не могу использовать Boost.Я бы хотел, но на самом деле не могу.
Я специально использую только CompareExchange и Incr / Decr.Не спрашивайте.
Я использую первый бит ref_ для хранения статуса конструкции (построено / не построено) и другие биты для подсчета ссылок.Это единственный способ управлять двумя переменными (подсчет ссылок и статус строительства) одновременно с помощью атомарных операций.
Некоторые вопросы сейчас:
РЕДАКТИРОВАТЬ: Некоторые предложили использоватьshared_ptr.Один для рабочего решения с shared_ptr!Обратите внимание, что мне нужно: ленивая конструкция и разрушение, когда никто больше не использует ее.