Author Topic: mutex as class member  (Read 81903 times)

bobjtowers

  • Newbie
  • *
  • Posts: 2
    • View Profile
mutex as class member
« on: December 13, 2010, 08:09:17 AM »
hi there,

consider this simple class (shown below)

It's just a callable functor class, implementing the func. call operator.
I find that when i declare a mutex inside this class, the compiler curses me...
.. uttering words like:

/usr/include/justthread/mutex: In copy constructor ‘functor::functor(const functor&)’:
threadId.cxx:19:   instantiated from ‘__jss::__0x::__invoker<_ResultType, _Callable, _Args>::__invoker(_Callable&, const __jss::__0x::__args_tuple<_OtherArgs ...>&) [with _OtherArgs = , _ResultType = void, _Callable = functor&, _Args = ]’

When i make the mutex global (line 17).. the code compiles and runs as expected.
I also tried wrapping the mutex in a unique_lock.  But ... no joy.

Is it not possible to define a mutex as a class member ?
Any suggestions.. warmly welcomed :)

Rob.


 17 // mutex m;
 18
 19 class functor {
 20     mutex m;
 21     // unique_lock<mutex> m;
 22 public:
 23     void operator()() {
 24         int loopCtr = 0;
 25         while (++loopCtr < 20){
 26             getThreadId(loopCtr);
 27         }
 28     }
 29     functor(){}
 30 private:
 31     void getThreadId(const int ctr){
 32         m.lock();
 33         try {
 34             thread::id thisThread = this_thread::get_id();
 35             cout << ctr << " - thisThread=" << thisThread << endl;
 36             m.unlock();
 37         } catch (...) {
 38             m.unlock();
 39         }
 40     }
 41 };

Anthony Williams

  • Administrator
  • Full Member
  • *****
  • Posts: 103
    • View Profile
    • just::thread C++ Thread Library
Re: mutex as class member
« Reply #1 on: December 13, 2010, 08:29:19 AM »
consider this simple class (shown below)

It's just a callable functor class, implementing the func. call operator.
I find that when i declare a mutex inside this class, the compiler curses me...
.. uttering words like:

/usr/include/justthread/mutex: In copy constructor ‘functor::functor(const functor&)’:
threadId.cxx:19:   instantiated from ‘__jss::__0x::__invoker<_ResultType, _Callable, _Args>::__invoker(_Callable&, const __jss::__0x::__args_tuple<_OtherArgs ...>&) [with _OtherArgs = , _ResultType = void, _Callable = functor&, _Args = ]’

When i make the mutex global (line 17).. the code compiles and runs as expected.
I also tried wrapping the mutex in a unique_lock.  But ... no joy.

Is it not possible to define a mutex as a class member ?
Any suggestions.. warmly welcomed :)
Quote

std::mutex is not copyable. That means that if you define a mutex as a class member then the compiler cannot implicitly define the copy constructor, and you get an error message like the one you show when you try and copy your class.

If you want to make your class copyable then you need to write a copy constructor that default-constructs the mutex. You might also want to lock the mutex on the source whilst you do the copy, so that you don't get a race condition.

However, if you are copying your functor onto a thread then you probably don't need a mutex, as the thread will be the only place that can access the copy that was running on the thread, so no synchronization is needed. The fact that you think you need synchronization suggests you intend to access the same object from multiple threads, in which case you probably want to pass the functor by reference using std::ref (or std::tr1::ref if std::ref is not available):

Code: [Select]
functor f;
std::thread t(std::ref(f));

Hope that helps,

Anthony

bobjtowers

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: mutex as class member
« Reply #2 on: December 14, 2010, 04:55:11 AM »
It does help, thanks for replying :)

This issue of the non-copy mutex really interests me.
I can't help wondering why it is non-copyable.
Is this issue to do with whether the mutex would be a deep vs shallow copy of the mutex ?
What danger or mischief is prevented by making a mutex non-copyable ?

Java has a unique intrinsic lock built into every object of every class.
To the best of knowledge, there are no special hazards associated with this scenario.
(but of-course, i don't know, what i don't know)

Rob.

Anthony Williams

  • Administrator
  • Full Member
  • *****
  • Posts: 103
    • View Profile
    • just::thread C++ Thread Library
Re: mutex as class member
« Reply #3 on: December 14, 2010, 03:35:26 PM »
It does help, thanks for replying :)

You're welcome

This issue of the non-copy mutex really interests me.
I can't help wondering why it is non-copyable.
Is this issue to do with whether the mutex would be a deep vs shallow copy of the mutex ?
What danger or mischief is prevented by making a mutex non-copyable ?

What does it mean to copy a mutex? Do you copy the lock state, so the same thread owns the lock as owned the original? If so, how does that thread know? I do not know of an OS that provides copyable mutexes. You might have a copyable handle to a mutex, which is equivalent to a pointer, but then all copies of the handle share the same underlying mutex.

When copying an object with a mutex, you probably want to create a new mutex for the new object rather than share the mutex, and the new mutex probably ought to be created unlocked, rather than copying the lock state. However, you probably do want to lock the mutex on the source object whilst you're copying, in order to avoid a data race on the other data members.

Java has a unique intrinsic lock built into every object of every class.
To the best of knowledge, there are no special hazards associated with this scenario.
(but of-course, i don't know, what i don't know)

It's true that you can synchronize on any object in Java, but most implementations will not create a mutex for every object --- they may share mutexes between objects or create them lazily on demand.

Also, in Java you do not copy most objects, you just pass round pointers instead. If you want to clone an object then you need to ensure that it is correctly synchronized.

Anthony