从析构函数释放boost :: mutex

时间:2012-01-14 13:41:53

标签: c++ destructor boost-thread boost-mutex

由于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 个答案:

答案 0 :(得分:1)

编辑:更新为更完整的示例。

其他人已经指出了你的“线程安全”的缺陷;我会尝试回答你的问题。

执行您要执行的操作的唯一正确方法是确保在尝试销毁向量本身之前已关闭所有线程。

我使用的常用方法是简单地使用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;
};

如果您正在寻找一个允许多个读者和编写者的更完整的线程安全数据结构,请随时查看我使用boost线程编写的队列。

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