Comme std::vector
n'est pas thread-safe, j'essayais de construire un très simple encapsulation autour de lui qui le rend thread-safe.Release boost :: mutex de destructor
Cela fonctionne plutôt bien, mais il y a un petit problème. Lorsque l'instance de la classe est en train d'être détruite et qu'un autre thread essaie toujours d'en lire des données, le thread reste suspendu indéfiniment dans le boost::mutex::scoped_lock lock(m_mutex);
Comment résoudre ce problème? Le mieux est de simplement déverrouiller le mutex afin que le thread qui s'y trouve puisse continuer à s'exécuter. Je n'ai pas défini de destructeur car jusqu'à présent, ce n'était pas nécessaire.
Voici mon code. Notez qu'il y a plus de méthodes que celles montrées ici, cela a été simplifié.
template<class T>
class SafeVector
{
public:
SafeVector();
SafeVector(const SafeVector<T>& other);
unsigned int size() const;
bool empty() const;
void clear();
T& operator[] (const unsigned int& n);
T& front();
T& back();
void push_back(const T& val);
T pop_back();
void erase(int i);
typename std::vector<T>::const_iterator begin() const;
typename std::vector<T>::const_iterator end() const;
const SafeVector<T>& operator= (const SafeVector<T>& other);
protected:
mutable boost::mutex m_mutex;
std::vector<T> m_vector;
};
template<class T>
SafeVector<T>::SafeVector()
{
}
template<class T>
SafeVector<T>::SafeVector(const SafeVector<T>& other)
{
this->m_vector = other.m_vector;
}
template<class T>
unsigned int SafeVector<T>::size() const
{
boost::mutex::scoped_lock lock(m_mutex);
return this->m_vector.size();
}
template<class T>
bool SafeVector<T>::empty() const
{
boost::mutex::scoped_lock lock(m_mutex);
return this->m_vector.empty();
}
template<class T>
void SafeVector<T>::clear()
{
boost::mutex::scoped_lock lock(m_mutex);
return this->m_vector.clear();
}
template<class T>
T& SafeVector<T>::operator[] (const unsigned int& n)
{
boost::mutex::scoped_lock lock(m_mutex);
return (this->m_vector)[n];
}
template<class T>
T& SafeVector<T>::front()
{
boost::mutex::scoped_lock lock(m_mutex);
return this->m_vector.front();
}
template<class T>
T& SafeVector<T>::back()
{
boost::mutex::scoped_lock lock(m_mutex);
return this->m_vector.back();
}
template<class T>
void SafeVector<T>::push_back(const T& val)
{
boost::mutex::scoped_lock lock(m_mutex);
return this->m_vector.push_back(val);
}
template<class T>
T SafeVector<T>::pop_back()
{
boost::mutex::scoped_lock lock(m_mutex);
T back = m_vector.back();
m_vector.pop_back();
return back;
}
template<class T>
void SafeVector<T>::erase(int i)
{
boost::mutex::scoped_lock lock(m_mutex);
this->m_vector.erase(m_vector.begin() + i);
}
template<class T>
typename std::vector<T>::const_iterator SafeVector<T>::begin() const
{
return m_vector.begin();
}
template<class T>
typename std::vector<T>::const_iterator SafeVector<T>::end() const
{
return m_vector.end();
}
Modifier je dois changer ma définition. Le conteneur n'est clairement pas sûr pour les threads comme indiqué précédemment. Ce n'est pas censé le faire - même si la nomenclature est trompeuse. Bien sûr, vous pouvez faire des choses qui ne sont pas du tout thread-safe! Mais un seul fil écrit dans le conteneur, 2 ou 3 sont lus. Cela fonctionne bien jusqu'à ce que j'essaie d'arrêter le processus. Je dois dire qu'un moniteur aurait été mieux. Mais le temps s'épuise et je ne peux pas changer cela jusque-là.
Toute idée est appréciée! Merci et salutations.
Je pense que vous avez des problèmes de filetage à un niveau supérieur. Cela semble être une erreur pour le thread 1 de penser qu'il est légitime de détruire un objet auquel le thread 2 a une référence et croit qu'il peut en lire. Et si le thread 1 réussissait réellement à détruire complètement l'objet et que _then_ thread 2 essayait de le lire? –
Le constructeur de copie ne devrait-il pas également verrouiller le vecteur * other *? –
Je serais intéressé de voir la mise en œuvre de l'opérateur d'affectation de copie, aussi. Il serait facile de l'obtenir de façon spectaculaire. –