Мое решение сравнивает объекты, а не массивы. Это будет работать так же, как у Томаша, поскольку массивы являются объектами, но без предупреждения:
Object.prototype.compare_to = function(comparable){
// Is the value being compared an object
if(comparable instanceof Object){
// Count the amount of properties in @comparable
var count_of_comparable = 0;
for(p in comparable) count_of_comparable++;
// Loop through all the properties in @this
for(property in this){
// Decrements once for every property in @this
count_of_comparable--;
// Prevents an infinite loop
if(property != "compare_to"){
// Is the property in @comparable
if(property in comparable){
// Is the property also an Object
if(this[property] instanceof Object){
// Compare the properties if yes
if(!(this[property].compare_to(comparable[property]))){
// Return false if the Object properties don't match
return false;
}
// Are the values unequal
} else if(this[property] !== comparable[property]){
// Return false if they are unequal
return false;
}
} else {
// Return false if the property is not in the object being compared
return false;
}
}
}
} else {
// Return false if the value is anything other than an object
return false;
}
// Return true if their are as many properties in the comparable object as @this
return count_of_comparable == 0;
}
Надеюсь, это поможет вам или кому-либо еще в поисках ответа.
Сделайте подсчет ссылок атомарным, и вам не потребуется никакой блокировки. В Windows можно использовать :: InterlockedIncrement и :: InterlockedDecrement. В C ++ 0x есть атомарный <>.
Если вы не знаете, что это конкретное узкое место, я бы просто использовал boost :: shared_ptr
Это очень быстро, однако есть небольшие дополнительные накладные расходы в дополнительном блоке управления, который выделено. С другой стороны, у этого есть много преимуществ:
boost
, что, если вы этого не сделаете, вы должны быть Также обратите внимание, вы, вероятно, не будете требуется блокировка чтения / записи для объекта с подсчетом ссылок. Разногласия минимальны, а дополнительные накладные расходы полностью подавят любые ваши преимущества.
osg, OpenSceneGraph имеет такую структуру.
вы наследуете свои классы от osg :: Referenced, и вам наплевать на деструктор даже в многопоточности.
вы просто создайте классы как:
osg::ref_ptr<MyClass> m = new MyClass();
вместо:
MyClass* m = new MyClass();
Основная проблема заключается в том, что вы не получаете ссылку до возврата CreateTexture. Если вы используете такое открытое кодирование, самый простой способ справиться с этим - установить блокировку TexPool, которая также используется при освобождении ссылок перед удалением, например:
// PSEUDOCODE WARNING: --refcnt MUST be replaced by an atomic decrement-and-test
// Likewise, AddRef() MUST use an atomic increment.
void DecRef() {
if (!--refcnt) {
lock();
if (!refcnt)
delete this;
unlock();
}
}
и:
Texture *CreateTexture(const std::string &file)
{
lock();
TexPoolIterator i = TexPool.find(file);
if(i != TexPool.end()) {
*i->AddRef();
unlock();
return *i;
}
unlock();
return new Texture(file);
}
Тем не менее, как и другие Как уже упоминалось, boost :: shared_ptr (также известный как std :: tr1 :: shared_ptr) реализует все это без блокировки, безопасным способом, а также имеет поддержку слабых указателей, которые помогут с вашим кешем текстур.
boost :: shared_ptr и Poco :: SharedPtr заключают эту идиому в отдельный интеллектуальный указатель.
Если вам нужен навязчивый подсчет ссылок, как вы продемонстрировали выше, AutoPtr Poco - хорошая работающая реализация.
] РЕДАКТИРОВАТЬ: Я бы добавил ссылки, но у меня была слишком низкая репутация. Найдите в Google любое из названий классов, и вы должны найти свой путь.
Если вы не хотите использовать ускорение или C ++ 0X, но по-прежнему хотите использовать безблокировочный счетчик ссылок, вы можете сделать это, включив правильный атомарный инкремент / атомный декремент для конкретной платформы ассемблерные процедуры в вашем коде. В качестве примера приведем класс AtomicCounter, который я использую для подсчета ссылок; он работает под наиболее распространенными ОС:
https://public.msli.com/lcs/muscle/html/AtomicCounter_8h_source.html
Да, это неприятный беспорядок из #ifdefs. Но это работает.
Вы хотели потокобезопасный или атомарный потокобезопасный? boot :: shared_ptr просто потокобезопасен. Вам все еще нужно «владеть» shared_ptr, чтобы безопасно его копировать.
Я сделал несколько экспериментальных вещей по атомарно-поточно-безопасному подсчету ссылок здесь, на http://atomic-ptr-plus.sourceforge.net/ , который может дать вам представление о том, в чем дело.
Ваш кеш должен использовать boost :: weak_ptr
или аналогичную конструкцию.
Взгляните на этот pdf: http://www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdf
Здесь описывается ссылка система подсчета, которая не требует блокировки. (Ну, вам нужно «приостанавливать» потоки по одному, что может считаться блокировкой.) Он также собирает циклы мусора. Недостаток в том, что это намного сложнее. Есть также несколько важных вещей, оставленных читателю в качестве упражнения. Например, что происходит, когда создается новый поток или удаляется старый, или как работать с по сути ациклическими объектами. (Если вы решите это сделать, дайте мне знать, как вы это делали.)
Я думаю, вам действительно нужны критические секции для этого конкретного проекта. Одно место, где это требуется, - это CreateTexture, потому что в противном случае вы рискуете иметь более одного идентичного объекта текстуры в системе. И вообще, если несколько потоков могут создавать и уничтожать одну и ту же текстуру, это делает ее «изменяемым общим состоянием».