There are two classes. Class A has a private member std::mutex m_. Class B has an instance of class A as its member.
The goal is to let class B to be able to use m_ (which is in class A).
I tried adding an accessor method in class A as below, but it gives error no matching function for call to 'std::unique_lock<std::mutex>::unique_lock(std::mutex)'.
Is above error because std::mutex is non-copyable?
What is the suggested way to expose the std::mutex in this case?
class A {
public:
// does not work
std::mutex getMutex() {
return m_;
}
private:
std::mutex m_;
}
class B {
A a;
void someMethod() {
...
std::unique_lock<std::mutex> lock(a.m_);
...
}
}
Is above error because std::mutex is non-copyable?
That is correct. A std::mutex cannot be copied or moved.
What is the suggested way to expose the std::mutex in this case?
In this case, you can just return by reference like
std::mutex& getMutex() {
return m_;
}
and use it like
std::unique_lock<std::mutex> lock(a.getMutex());
Related
I need to work with the same mutex and unique_lock across the main function and class instances. However, I am having trouble assigning the mutex/unique_lock address to a class member variable (that is a mutex&).
This is what I have:
Worker.h
class Worker
{
private:
std::mutex &m_mu;
std::unique_lock<std::mutex> &locker;
public:
void start(std::mutex &mu, std::unique_lock<std::mutex> &locker);
};
Worker.cpp
void Worker::start(std::mutex &mu, std::unique_lock<std::mutex> &locker)
{
this->mu = mu; // error
this->locker = locker; // error
}
I tried doing this->mu(mu); but that doesn't work either. Is there anything I can do to make this work?
Thanks.
You need to pass the mutex reference when you construct your class.
Worker::Worker(std::mutex &mu, std::unique_lock<std::mutex> &locker)
:m_mu(mu), locker(locker)
{}
That's the only place you can initialize a reference. Once it's constructed, you cannot change what it references.
Why do you need the locker? The mutex makes the synchronization, the lock is just a RAII object to ease acquiring the mutex.
You don't need to pass the lock object to the function. As long as the class is referring to the correct mutex you can lock the mutex inside the function like this:
class Worker
{
private:
std::mutex& m_mu;
public:
Worker(std::mutex& mu): m_mu(mu) {} // bind reference during initialization
void start();
};
// Worker.cpp
void Worker::start()
{
std::unique_lock<std::mutex> locker(m_mu); // lock the shared resource
// Do something with it here
}
int main()
{
std::mutex mu;
std::vector<Worker> workers(4, Worker(std::ref(mu)));
// etc...
}
I have a problem with passing a mutex to my class. I have a class named Test with the a member variable called m_Mutex. In the constructor I want to transfer the parameter mutex to m_Mutex.
My class:
#include <mutex>
class Test
{
public:
Test(mutex &mtx) :
m_Mutex(mtx)
{
}
private:
mutex m_Mutex;
};
My main:
int main()
{
mutex mutex1;
Test t(mutex1);
return 0;
}
Error:
function "std::mutex::mutex(const std::mutex &)" (declared at line 88
of "c:\Program Files (x86)\Microsoft Visual
Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\include\mutex")
cannot be referenced -- it is a deleted function
Why am I getting this error and how can I fix it that I am able to pass the mutex?
In short terms: you can't. Mutexes are neither copyable nor movable. And they aren't for a good reason. If however you want to achieve this nontheless, you might pass it by using a unique_ptr:
class A {
unique_ptr<mutex> mutexPtr;
A(unique_ptr<mutex> ptr) : mutexPtr(std::move(ptr)) { }
};
A a{std::make_unique<mutex>()};
Note that if you want to share the mutex between different objects, you should use shared_ptr or weak_ptr instead.
In the constructor I want to transfer the parameter mutex to m_Mutex
Unfortunately you can't. std::mutex is not copyable and not moveable. One thing you can do if you want to declare the mutex somewhere else is to store a reference to the mutex like
class Test
{
public:
Test(mutex &mtx) :
m_Mutex(mtx)
{
}
private:
mutex& m_Mutex;
};
#include <mutex>
class Test
{
public:
Test(std::mutex &mtx) :
m_Mutex(mtx)
{
}
private:
std::mutex &m_Mutex; // note the "&"
};
int main()
{
std::mutex mutex1;
Test t(mutex1);
return 0;
}
Just keep mutex inside your class (probably as static member) and if you need to allow other classes to use it provide access:
class Test
{
public:
Test() {}
std::mutex &mux() { return m_Mutex; }
private:
mutex m_Mutex;
};
or even this:
class Test {
public:
using lock_t = std::scoped_lock<std::mutex>;
Test() {}
lock_t lock() { return lock_t( m_Mutex ); }
private:
mutex m_Mutex;
};
usage:
Test t;
{
auto lock = t.lock();
// object t is locked till end of the block
}
Just make it a reference
Your mutex must be the same for all instances of your class, if it's not the case the lock you do in one instance of your class won't be active for the other one.
#include <mutex>
#include <iostream>
using namespace std;
class Test
{
public:
Test(mutex &mtx) :
m_Mutex(mtx)
{
m_Mutex.lock();
i++;
cout << "Test " <<i<<endl;
m_Mutex.unlock();
}
private:
mutex& m_Mutex;
static int i;
};
int Test::i =0;
int main()
{
mutex mutex1;
Test t1(mutex1);
Test t2(mutex1);
return 0;
}
see it live : https://wandbox.org/permlink/6YJFG3MI7m7RbfoL
Working case:
template<typename T>
class threadsafe_queue
{
private:
mutable std::mutex mut;
std::queue<T> data_queue;
public:
threadsafe_queue()
{}
threadsafe_queue(const threadsafe_queue& other)
{
std::lock_guard<std::mutex> lk(other.mut);
data_queue=other.data_queue;
}
};
Case that should fail: Note no mutable on std::mutex mut;
template<typename T>
class threadsafe_queue
{
private:
std::mutex mut;
std::queue<T> data_queue;
public:
threadsafe_queue()
{}
threadsafe_queue(const threadsafe_queue& other)
{
std::lock_guard<std::mutex> lk(other.mut);
data_queue=other.data_queue;
}
};
I have tried the both cases listed above and they compile without problems. I assume internally the lock_guard calls mutex::lock function which itself is NOT a const function.
Question> why can we lock the mutex from a const object in the copy constructor?
The first example compiles because the mutex is qualified to be mutable. That means that this field can be modified, mutated, without the containing object considered to have been changed. So, in a sense, the mutex' state is not "part of the queue". The compiler allows const methods to modify mutable members.
The second example only compiles as long as you don't actually try to instantiate the class and use that method. If you do, it fails. Templates are magic...
I have the following class that has the private member - QMutex - m_mutex_A;
class A
{
public:
QMutex get_handle();
private:
QMutex m_mutex_A;
}
QMutex A::get_handle()
{
return m_mutex_A;
}
However, on building this snippet, I get the problem saying that the error: 'QMutex::QMutex(const QMutex&)' is private
On google, I found that one of the way is to make QMutex m_mutex_A; as
mutable QMutex m_mutex_A; However, this doesn't work. Another strange part is that when I move this m_mutex_A to public then there is no problem. Also, the code works. What is the issue here? Can you please throw some light on it? I guess, I am missing some fundamentals here.
You'll need to return a reference. QMutex doesn't provide an accessible copy constructor (which wouldn't make sense of course):
class A {
public:
QMutex& get_handle() { return m_mutex_A; }
private:
QMutex m_mutex_A;
};
The mutable keyword is needed if you want to use the mutex internally within const methods.
The error is telling you that the copy constructor for QMutex is private, so while you can declare the object as a private member, you can't return a copy in get_handle. You could, however return a reference: QMutex&
You can read about why a copy constructor is declared private here.
I'm guessing that you've misunderstood the context of the google article with reference to mutable. The mutable keyword allows modification of a variable from within a const function as well as "the differentiation of bitwise const and logical const" as answered here.
Mutexes are not supposed to be copied. A mutex is not a handle. Don't treat it like one.
If a mutex in class A serializes access to it, then it should only be used in the methods within that class. The users of the class should not need to worry about it. When making copies of the class, the mutex must not be copied - thus you must write your own copy and move constructors, and an assignment operator.
class A {
mutable QMutex m_mutex;
int m_foo;
bool m_bar;
public:
A() : m_foo(0), m_bar(false) {}
A(const A& other) { *this = other; }
A& operator=(const A & rhs) {
if (this == &rhs) return *this;
// This guarantees that mutexes for two instances are
// always acquired in the same order. This prevents
// a certain class of deadlocks.
// See http://www.justsoftwaresolutions.co.uk/threading/acquiring-multiple-locks-without-deadlock.html
QMutexLocker lock1(qMin(&rhs.m_mutex, &m_mutex));
QMutexLocker lock2(qMax(&rhs.m_mutex, &m_mutex));
m_foo = rhs.m_foo;
m_bar = rhs.m_bar;
}
void setFoo(int foo) {
QMutexLocker lock(&m_mutex);
m_foo = foo;
}
int foo() const {
QMutexLocker lock(&m_mutex);
return m_foo;
}
void setBar(bool bar) {
QMutexLocker lock(&m_mutex);
m_bar = bar;
}
bool bar() const {
QMutexLocker lock(&m_mutex);
return m_bar;
}
};
All of the public methods are thread safe.
I have a class that is shared between several projects, some uses of it are single-threaded and some are multi-threaded. The single-threaded users don't want the overhead of mutex locking, and the multi-threaded users don't want to do their own locking and want to be able to optionally run in "single-threaded mode." So I would like to be able to select between real and "dummy" mutexes at runtime.
Ideally, I would have a shared_ptr<something> and assign either a real or fake mutex object. I would then "lock" this without regard to what's in it.
unique_lock<something> guard(*mutex);
... critical section ...
Now there is a signals2::dummy_mutex but it does not share a common base class with boost::mutex.
So, what's an elegant way to select between a real mutex and a dummy mutex (either the one in signals2 or something else) without making the lock/guard code more complicated than the example above?
And, before you point out the alternatives:
I could select an implementation at compile time, but preprocessor macros are ugly and maintaining project configurations is painful for us.
Users of the class in a multi-threaded environment do not want to take on the responsibility of locking the use of the class rather than having the class do its own locking internally.
There are too many APIs and existing usages involved for a "thread-safe wrapper" to be a practical solution.
How about something like this?
Its untested but should be close to OK.
You might consider making the template class hold a value rather than a pointer
if your mutexes support the right kinds of constructions. Otherwise you could specialise the MyMutex class to get value behaviour.
Also it's not being careful about copying or destruction .. I leave that as an exercise to the reader ;) ( shared_ptr or storing a value rather than a pointer should fix this)
Oh and the code would be nicer using RAII rather than explicit lock/unlock... but that's a different question.I assume thats what the unique_lock in your code does?
struct IMutex
{
virtual ~IMutex(){}
virtual void lock()=0;
virtual bool try_lock()=0;
virtual void unlock()=0;
};
template<typename T>
class MyMutex : public IMutex
{
public:
MyMutex(T t) : t_(t) {}
void lock() { t_->lock(); }
bool try_lock() { return t_->try_lock(); }
void unlock() { t_->unlock(); }
protected:
T* t_;
};
IMutex * createMutex()
{
if( isMultithreaded() )
{
return new MyMutex<boost::mutex>( new boost::mutex );
}
else
{
return new MyMutex<signal2::dummy_mutex>( new signal2::dummy_mutex );
}
}
int main()
{
IMutex * mutex = createMutex();
...
{
unique_lock<IMutex> guard( *mutex );
...
}
}
Since the two mutex classes signals2::dummy_mutex and boost::mutex don't share a common base class you could use something like "external polymorphism" to allow to them to be treated polymorphically. You'd then use them as locking strategies for a common mutex/lock interface. This allows you to avoid using "if" statements in the lock implementation.
NOTE: This is basically what Michael's proposed solution implements. I'd suggest going with his answer.
Have you ever heard about Policy-based Design ?
You can define a Lock Policy interface, and the user may choose which policy she wishes. For ease of use, the "default" policy is precised using a compile-time variable.
#ifndef PROJECT_DEFAULT_LOCK_POLICY
#define PROJECT_DEFAULT_LOCK_POLICY TrueLock
#endif
template <class LP = PROJECT_DEFAULT_LOCK_POLICY>
class MyClass {};
This way, your users can choose their policies with a simple compile-time switch, and may override it one instance at a time ;)
This is my solution:
std::unique_lock<std::mutex> lock = dummy ?
std::unique_lock<std::mutex>(mutex, std::defer_lock) :
std::unique_lock<std::mutex>(mutex);
Is this not sufficient?
class SomeClass
{
public:
SomeClass(void);
~SomeClass(void);
void Work(bool isMultiThreaded = false)
{
if(isMultiThreaded)
{
lock // mutex lock ...
{
DoSomething
}
}
else
{
DoSomething();
}
}
};
In general, a mutex is only needed if the resource is shared between multiple processes. If an instance of the object is unique for a (possibly multi-threaded) process, then a Critical Section is often more appropriate.
In Windows, the single-threaded implementation of a Critical Section is a dummy one. Not sure what platform you are using.
Just FYI, here's the implementation I ended up with.
I did away with the abstract base class, merging it with the no-op "dummy" implementation. Also note the shared_ptr-derived class with an implicit conversion operator. A little too tricky, I think, but it lets me use shared_ptr<IMutex> objects where I previously used boost::mutex objects with zero changes.
header file:
class Foo {
...
private:
struct IMutex {
virtual ~IMutex() { }
virtual void lock() { }
virtual bool try_lock() { return true; }
virtual void unlock() { }
};
template <typename T> struct MutexProxy;
struct MutexPtr : public boost::shared_ptr<IMutex> {
operator IMutex&() { return **this; }
};
typedef boost::unique_lock<IMutex> MutexGuard;
mutable MutexPtr mutex;
};
implementation file:
template <typename T>
struct Foo::MutexProxy : public IMutex {
virtual void lock() { mutex.lock(); }
virtual bool try_lock() { return mutex.try_lock(); }
virtual void unlock() { mutex.unlock(); }
private:
T mutex;
};
Foo::Foo(...) {
mutex.reset(single_thread ? new IMutex : new MutexProxy<boost::mutex>);
}
Foo::Method() {
MutexGuard guard(mutex);
}
Policy based Option:
class SingleThreadedPolicy {
public:
class Mutex {
public:
void Lock() {}
void Unlock() {}
bool TryLock() { return true; }
};
class ScopedGuard {
public:
ScopedGuard(Mutex& mutex) {}
};
};
class MultithreadingPolicy {
public:
class ScopedGuard;
class Mutex {
friend class ScopedGuard;
private:
std::mutex mutex_;
public:
void Lock() {
mutex_.lock();
}
void Unlock() {
mutex_.unlock();
}
bool TryLock() {
return mutex_.try_lock();
}
};
class ScopedGuard {
private:
std::lock_guard<std::mutex> lock_;
public:
ScopedGuard(Mutex& mutex) : lock_(mutex.mutex_) {}
};
};
Then it can be used as follows:
template<class ThreadingPolicy = SingleThreadedPolicy>
class MyClass {
private:
typedef typename ThreadingPolicy::Mutex Mutex;
typedef typename ThreadingPolicy::ScopedGuard ScopedGuard;
Mutex mutex_;
public:
void DoSomething(){
ScopedGuard guard(mutex_);
std::cout<<"Hello World"<<std::endl;
}
};