Релиз буст :: мьютекс от деструктора - PullRequest
1 голос
/ 14 января 2012

Поскольку std::vector не является потокобезопасным, я пытался построить вокруг него очень простую инкапсуляцию, которая делает его поточно-ориентированным.

Это работает довольно хорошо, ноесть одна маленькая проблемаКогда экземпляр класса уничтожается, а другой поток все еще пытается прочитать данные из него, поток продолжает зависать навсегда в boost::mutex::scoped_lock lock(m_mutex);

Как я могу решить эту проблему?Лучше всего просто разблокировать мьютекс, чтобы поток, висящий в нем, мог продолжать выполняться.Я не определил деструктор, потому что до сих пор он не требовался.

Вот мой код.Обратите внимание, что здесь больше методов, чем показано здесь, это упрощено.

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();
}

Редактировать Мне нужно изменить свое определение.Контейнер явно не является поточно-ориентированным, как указано выше.Это не должно быть сделано - даже если номенклатура вводит в заблуждение.Конечно, вы можете делать с ним вещи, которые не являются потокобезопасными вообще!Но только один поток пишет в контейнер, 2 или 3 читают из него.Это работает хорошо, пока я не попытаюсь остановить процесс.Я должен заявить, что монитор был бы лучше.Но время уходит, и я не могу изменить это до тех пор.

Любая идея приветствуется!Спасибо и всего наилучшего.

1 Ответ

1 голос
/ 15 января 2012

РЕДАКТИРОВАТЬ: Обновлено, чтобы быть более полным примером.

Другие указали на недостатки с вашей "безопасности потока;"Я попытаюсь ответить на ваш вопрос.

Единственный правильный способ сделать то, что вы намеревались сделать, это убедиться, что все ваши потоки были закрыты, прежде чем пытаться уничтожить сам вектор.

Обычный метод, который я использовал, - просто использовать RAII для определения порядка строительства и разрушения.

void doSomethingWithVector(SafeVector &t_vec)
{
  while (!boost::this_thread::interruption_requested())
  {
    //operate on t_vec
  }
}

class MyClassThatUsesThreadsAndStuff
{
  public:
    MyClassThatUsesThreadsAndStuff()
      : m_thread1(&doSomethingWithVector, boost::ref(m_vector)),
        m_thread2(&doSomethingWithVector, boost::ref(m_vector))
    {
      // RAII guarantees that the vector is created before the threads
    }

    ~MyClassThatUsesThreadsAndStuff()
    {
      m_thread1.interrupt();
      m_thread2.interrupt();
      m_thread1.join();
      m_thread2.join();
      // RAII guarantees that vector is freed after the threads are freed
    }

  private:
    SafeVector m_vector;
    boost::thread m_thread1;
    boost::thread m_thread2;
};

Если вы ищете более полную поточно-ориентированную структуру данных, которая позволяет нескольким читателям и писателям, не стесняйтесь проверить очередь, которую я написал, используя потоки повышения некоторое время назад.

http://code.google.com/p/crategameengine/source/browse/trunk/include/mvc/queue.hpp

...