Search code examples
c++multithreadingboostboost-threadboost-mutex

Using boost::mutex as a private member of class


I have a class that contains a boost::mutex as a private member. It becomes locked when you call one of its public functions and unlocks when the function exits. This is to provide synchronous access to the object's internals.

class StringDeque
{
  boost::mutex mtx;
  std::deque<string> string_deque;
public:
  StringDeque() { }

  void addToDeque(const string& str_to_add)
  {
    boost::lock_guard<boost::mutex> guard(mtx);
    string_deque.push(str_to_add);
  }

  string popFromDeque()
  {
    boost::lock_guard<boost::mutex> guard(mtx);
    string popped_string = string_deque.front();
    string_deque.pop();
    return popped_string;
  }
};

This class isn't meant to be particularly useful but I am just playing around with mutexes and threads.

I have a main() that also has another function defined that pops strings from the class and prints them in a thread. It will repeat this 10 times and then return from the function. Once again, this is purely for testing purposes. It looks like this:

void printTheStrings(StringDeque& str_deque)
{
    int i = 0;
    while(i < 10)
    {
      string popped_string = str_deque.popFromDeque();
      if(popped_string.empty())
      {
        sleep(1);
        continue;
      }
      cout << popped_string << endl;
      ++i;
    }
}

int main()
{
  StringDeque str_deque;
  boost::thread the_thread(printTheStrings, str_deque);
  str_deque.addToDeque("Say your prayers");
  str_deque.addToDeque("Little One");
  str_deque.addToDeque("And Don't forget My Son");
  str_deque.addToDeque("To include everyone");
  str_deque.addToDeque("I tuck you in");
  str_deque.addToDeque("Warm within");
  str_deque.addToDeque("Keep you free from sin");
  str_deque.addToDeque("Until the sandman he comes");
  str_deque.addToDeque("Sleep with one eye open");
  str_deque.addToDeque("Gripping your pillow tight");
  the_thread.join();
}

The error I keep getting is that boost::mutex is noncopyable. The printTheStrings() function takes a reference so I am a little confused as to why this is trying to copy the object.

I have read up a bit on this and one solution I keep reading is to make the boost::mutex a static private member of the object. However, this defeats the purpose of my mutex since I want it to be on an object-by-object basis rather than a class variable.

Is this just bad use of mutexes? Should I just be rethinking this entire application?

EDIT:

I just discovered condition_variable which should serve my purpose a lot better to have the thread wait until there is something actually in the deque before waking up to pop from the deque and print it. All the examples that I see define these mutexes and condition_variable objects at a global scope. This seems very... not object-oriented in my opinion. Even the examples straight from Boost themselves show that it is done in this way. Is this really how other people use these objects?


Solution

  • You are correct that printToString takes the StringQueue by reference. Your problem is that boost::thread take its arguments by value. To force it to take the arguments by reference you will need to modify things to:

    boost::thread the_thread(printTheStrings, boost::ref(str_deque));
    

    As an aside, from C++11 onwards, threads are part of the standard library. You should probably use std::thread instead