Reputation: 223
I'm trying to implement what I think is a fairly simple design. I have a bunch of objects, each containing a std::map and there will be multiple processes accessing them. I want to make sure that there is only one insert/erase to each of these maps at a time.
So I've been reading about boost::thread and class member mutexes and using bind to pass to class member which are all new things to me. I started with a simple example from a Dr. Dobbs article and tried modifying that. I was getting all kinds of compiler errors due to my Threaded object having to be noncopyable. After reading up on that, I decided I can avoid the hassle by keeping a pointer to a mutex instead. So now I have code that compiles but results in the following error:
/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
Now I'm really stuck and would really appreciate help with the code as well as comments on where I'm going wrong conceptually. I realize there are some answered questions around these issues here already but I guess I'm still missing something.
#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;
}
Upvotes: 1
Views: 1308
Reputation: 39294
Conceptually, I think you do have a problem. Copying a std::shared_ptr will just increase its reference count, and the different objects will all use the same underlying mutex - meaning that whenever one of your objects is used, none of the rest of them can be used.
You, on the other hand, need each object to get its own mutex guard which is unrelated to other objects mutex guards.
What you need is to keep the mutex defined in the class private section as it is - but ensure that your copy constructor and copy assignment operator are overloaded to create a new one from scratch - one bearing no relation to the mutex in the object being copied/assigned from.
Upvotes: 1
Reputation: 29055
It looks like you're missing a constructor in your Threaded class that creates the mutex that _mx is intended to point at. In its current state (assuming you ran this code just as it is), the default constructor for Threaded calls the default constructor for shared_ptr, resulting in a null pointer (which is then dereferenced in your count() function.
You should add a constructor along the following lines:
Threaded::Threaded(int id)
: _mx(new boost::mutex())
, _mID(id)
{
}
Then you could remove the argument from your count function as well.
Upvotes: 2
Reputation: 20472
A mutex is non-copyable for good reasons. Trying to outsmart the compiler by using a pointer to a mutex is a really bad idea. If you succeed, the compiler will fail to notice the problems, but they will still be there and will turn round and bite you at runtime.
There are two solutions
There are advantages for both - I prefer the second.
For some more discussion of this, see my answer here mutexes with objects
Upvotes: 1