В настоящее время я пытаюсь передать однопотоковую программу в многопоточность. Это программное обеспечение интенсивно использует объекты «refCounts», что приводит к некоторым проблемам в многопоточности. Я ищу какой-то шаблон дизайна или что-то, что может решить мою проблему.
Основная проблема - удаление объекта между потоками, обычно удаление только уменьшает счетчик ссылок, а когда refcount равен нулю, тогда объект удаляется. Это хорошо работает в монопоточной программе и позволяет значительно улучшить производительность при копировании большого объекта.
Однако в многопоточности два потока могут захотеть удалить один и тот же объект одновременно, поскольку объект защищен мьютексом, только один поток удаляет объект и блокирует другой. Но когда он освобождает мьютекс, другой поток продолжает выполнение с недопустимым (освобожденным объектом), что приводит к повреждению памяти.
Вот пример с этим классом RefCountingObject
class RefCountedObject
{
public:
RefCountedObject()
: _refCount( new U32(1) )
{}
RefCountedObject( const RefCountedObject& obj )
: _refCount( obj._refCount )
{
ACE_Guard< ACE_Mutex > guard( _refCountMutex );
++(*_refCount);
}
~RefCountedObject()
{
Destroy();
}
RefCountedObject& operator=( const RefCountedObject& obj )
{
if( this != &obj )
{
Destroy();
ACE_Guard< ACE_Mutex > guard( _refCountMutex );
_refCount = obj._refCount;
++(*_refCount);
}
return *this;
}
private:
void Destroy()
{
ACE_Guard< ACE_Mutex > guard( _refCountMutex ); // thread2 are waiting here
--(*_refCount); // This cause a free memory write by the thread2
if( 0 == *_refCount )
delete _refCount;
}
private:
mutable U32* _refCount;
mutable ACE_Mutex _refCountMutex; // BAD: this mutex only protect the refCount pointer, not the refCount itself
};
Предположим, что два потока хотят удалить один и тот же RefCountsObject, оба находятся в ~ RefCountingObject и вызывают Destroy (), первый поток заблокировал мьютекс, а другой ожидает. После удаления объекта первым потоком второй продолжит выполнение и вызовет свободную запись в память.
Кто-нибудь сталкивался с подобной проблемой и нашел решение?
Спасибо всем за помощь, я осознаю свою ошибку:
Мьютекс защищает только указатель refCount, а не сам refCount! Я создал класс RefCount, который защищен мьютексом. Теперь мьютекс распределяется между всеми объектами refCounts.
Теперь все отлично работает.