5

I would like to lock the keys/index in another map like this:

std::map<int, boost::mutex> pointCloudsMutexes_;
pointCloudsMutexes_[index].lock();

However, I am getting the following error:

/usr/include/c++/4.8/bits/stl_pair.h:113: error: no matching function for call to 'boost::mutex::mutex(const boost::mutex&)'
       : first(__a), second(__b) { }
                               ^

It seems to work with std::vector, but not with std::map. What am I doing wrong?

jotik
  • 17,044
  • 13
  • 58
  • 123
Raaj
  • 363
  • 1
  • 3
  • 12
  • 2
    one wonders what requirements have led to the design decision that a map of mutexes is a valid solution. There's probably a much more elegant way to achieve what you want. – Richard Hodges Apr 07 '16 at 07:50
  • A concurrent hashmap – Raaj Apr 08 '16 at 09:55
  • This design won't be a concurrent hash map. It will be a non-concurrent map of mutexes. You need to wrap the entire map and protect it with just one mutex. – Richard Hodges Apr 08 '16 at 13:07
  • That is poor design. That way to access one key/value I need to lock the entire mutex? – Raaj Apr 11 '16 at 02:18
  • In order to *find or insert one*, yes. Otherwise you will have a data race when doing either of these things. – Richard Hodges Apr 11 '16 at 07:02

2 Answers2

4

In C++ before C++11, the mapped type of a std::map must be both default-constructible and copy-constructible, when calling operator[]. However, boost::mutex is explicitly designed not to be copy-constructible, because it is generally unclear what the semantics of copying a mutex should be. Due to boost::mutex not being copyable, insertion of such value using pointCloudsMutexes_[index] fails to compile.

The best workaround is to use some shared pointer to boost::mutex as the mapped type, e.g:

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

struct MyMutexWrapper {
    MyMutexWrapper() : ptr(new boost::mutex()) {}
    void lock() { ptr->lock(); }
    void unlock() { ptr->unlock(); }
    boost::shared_ptr<boost::mutex> ptr;
};

int main() {
    int const index = 42;
    std::map<int, MyMutexWrapper> pm;
    pm[index].lock();
}

PS: C++11 removed the requirement for the mapped type to be copy-constructible.

jotik
  • 17,044
  • 13
  • 58
  • 123
  • you say `"C++11 removed the requirement for the mapped type to be copy-constructible"`, so author's code should compile under c++11? – Alexey Andronov Apr 07 '16 at 08:01
  • @AlexeyAndronov yes. Just tried the code example from the question, and it does compile when index is an `int`. – jotik Apr 07 '16 at 08:04
  • it doesn't on my MSVS2015 update2 with `std::map` and `std::mutex` though X_x – Alexey Andronov Apr 07 '16 at 08:06
  • Complies well with `std::mutex` online [here](http://gcc.godbolt.org/#compilers:!((compiler:g530,options:'-std%3Dc%2B%2B11',source:'%23include+%3Cmutex%3E%0A%23include+%3Cmap%3E%0A%0Aint+main()+%7B%0A+++int+index+%3D+42%3B%0A+++std::map%3Cint,+std::mutex%3E+pointCloudsMutexes_%3B%0A+++pointCloudsMutexes_%5Bindex%5D.lock()%3B%0A%7D')),filterAsm:(commentOnly:!t,directives:!t,labels:!t),version:3) and [here](http://www.cpp.sh/3mcuu). – jotik Apr 07 '16 at 08:12
  • you're right, I was playing around with `pointCloudsMutexes_.emplace(index, std::mutex());` which still doesn't compile, but that's the other problem (linked to `std::pair` it seems) – Alexey Andronov Apr 07 '16 at 08:20
  • unfortunately, I am unable to use c++11..because some libraries I use like Point Cloud Library break under it – Raaj Apr 07 '16 at 08:26
  • My whole purpose is to create a concurrent hash map. There are no implementations online as of now for non c++11 code. Are you absolutely sure that using shared pointers with boost mutexes will work? – Raaj Apr 07 '16 at 08:27
  • @Raaj The example in my answer works in older versions of C++ as well. – jotik Apr 07 '16 at 08:28
  • Thanks. I assume that when I am reading and writing my hashmap, I would need to lock it in both cases – Raaj Apr 08 '16 at 10:05
  • This design won't be a concurrent hash map. It will be a non-concurrent map of mutexes. You need to wrap the entire map and protect it with just one mutex. – Richard Hodges Apr 08 '16 at 13:07
1

Map require a copy constructor,but unfortunately boost::mutex has no public copy constructor. Mutex declared as below:

class mutex
{
private:
    pthread_mutex_t m;
public:
    BOOST_THREAD_NO_COPYABLE(mutex)

I don't think vector works either, it should have same problem. Can you push_back an boost::mutex into vector?

jotik
  • 17,044
  • 13
  • 58
  • 123
Dean Song
  • 341
  • 1
  • 10