类成员互斥断言失败

时间:2012-02-17 20:22:21

标签: c++ multithreading class boost mutex

我正在尝试实现我认为相当简单的设计。我有一堆对象,每个对象都包含一个std :: map,并且会有多个进程访问它们。我想确保每次只对这些地图进行一次插入/擦除。

所以我一直在阅读boost :: thread和类成员互斥体,并使用bind传递给类成员,这对我来说都是新事物。我从a Dr. Dobbs article的一个简单示例开始,并尝试修改它。由于我的Threaded对象必须是不可复制的,我得到了各种编译器错误。在阅读完之后,我决定通过保持指向互斥锁的指针来避免麻烦。所以现在我有编译的代码但导致以下错误:

/usr/include/boost/shared_ptr.hpp:419:
    T* boost::shared_ptr< <template-parameter-1-1> >::operator->() const
    [with T = boost::mutex]: Assertion `px != 0' failed.  Abort

现在我真的被卡住了,非常感谢代码的帮助以及对我在概念上出错的地方的评论。我知道这里已经有一些关于这些问题的回答问题,但我想我仍然缺少一些东西。

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <map>

using namespace std;

class Threaded {
public:
  std::map<int,int> _tsMap;

  void count(int id) {
    for (int i = 0; i < 100; ++i) {
      _mx->lock();
      //std::cout << id << ": " << i << std::endl;      
      _tsMap[i] ++;
      _mx->unlock();
    }
  }

private:
  boost::shared_ptr<boost::mutex> _mx;
};


int main(int argc, char* argv[]) {
  Threaded th;
  int i = 1;
  boost::thread thrd1(boost::bind(&Threaded::count, &th, 1));
  //boost::thread thrd2(boost::bind(&th.count, 2));
  thrd1.join();
  //thrd2.join();

  return 0;
}

3 个答案:

答案 0 :(得分:2)

看起来你在Threaded类中缺少一个构造函数,它创建了_mx指向的互斥锁。在当前状态下(假设您运行此代码),Threaded的默认构造函数调用shared_ptr的默认构造函数,从而产生一个空指针(然后在count()函数中取消引用。

您应该沿着以下行添加构造函数:

Threaded::Threaded(int id)
  : _mx(new boost::mutex())
  , _mID(id) 
{
}

然后你也可以从你的计数函数中删除参数。

答案 1 :(得分:1)

互斥是不可复制的,原因很充分。尝试通过使用指向互斥锁的指针来超越编译器是一个非常糟糕的主意。如果你成功了,编译器将无法注意到这些问题,但是它们仍然存在,并且会在运行时转向并咬你。

有两种解决方案

  • 将互斥锁存储在您的班级中作为静态
  • 将互斥锁存储在您的课程之外。

两者都有优势 - 我更喜欢第二种。

有关此问题的更多讨论,请参阅我的答案mutexes with objects

答案 2 :(得分:1)

从概念上讲,我认为你确实遇到了问题。复制std :: shared_ptr只会增加其引用计数,并且不同的对象都将使用相同的底层互斥锁 - 这意味着无论何时使用其中一个对象,都不能使用其余的对象。

另一方面,你需要每个对象获得自己的互斥锁,这与其他对象互斥守卫无关。

你需要的是保持在类私有部分中定义的互斥锁原样 - 但是要确保你的复制构造函数和复制赋值运算符被重载以从头创建一个新的 - 一个与该互斥体无关。正在复制/分配的对象。