I have following code:
class Class
{
public:
std::string Read()
{
std::lock_guard<std::mutex> lock(mutex_);
return data_;
}
private:
std::mutex mutex_;
std::string data_;
};
What will be executed first - will a local copy (temporary) be created of the data_ string on the stack as a result of the function and then the lock will release the mutex, or will it be other way?
If so, does following line resolve the problem?
return std::string(data_);
Mutex is supposed to protect concurrent read/write of the data_, so that those operations do not interfere.
The function returns the data_ as an rvalue, hence the result here will be calculated from the data_ member before the destructor of lock is executed (as the function exits) and the mutex_ released.
Is a temporary (the return value) calculated before the mutex is released? Yes.
Is return std::string(data_); required? No.
Related
In the book "Concurrency in Action", there's an implementation of thread-safe stack where mutex is acquired/locked upon entering pop() and empty() functions like shown below:
class threadsafe_stack {
private:
std::stack<T> data;
mutable std::mutex m;
public:
//...
void pop(T& value) {
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
value = std::move(data.top());
data.pop();
}
bool empty() const {
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
};
My question is, how does this code not run into a deadlock, when a thread, that has acquired the lock upon entering pop() is calling empty() which is protected by mutex as well? If lock() is called by the thread that already owns the mutex, isn't that undefined behavior?
how does this code not run into a deadlock, when a thread, that has acquired the lock upon entering pop() is calling empty() which is protected by mutex as well?
Because you are not calling empty member function of threadsafe_stack but you are calling empty() of class std::stack<T>. If the code would be:
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if(empty()) // instead of data.empty()
throw empty_stack();
value = std::move(data.top());
data.pop();
}
Then, it would be undefined behavior:
If lock is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock. An implementation that can detect the invalid usage is encouraged to throw a std::system_error with error condition resource_deadlock_would_occur instead of deadlocking.
Learn about recursive and shared mutex.
Not 100% sure what you mean, I guess you mean calling pop and empty sequentially in the same thread? Like in
while(!x.empty()) x.pop();
std::lock_guard follows RAII. This means the constructor
std::lock_guard<std::mutex> lock(m);
will acquire/lock the mutex and the destructor (when lock goes out of scope) will release/unlock the mutex again. So it's unlocked at the next function call.
Inside pop only data.empty() is called, which is not protected by a mutex. Calling this->empty() inside pop would indeed result in undefined behaviour.
You would be correct if pop would call this->empty. Locking the same mutex twice via a std::lock_guard is undefined behavior unless the locked mutex is a recursive one.
From cppreference on the constructor (the one that is used in the example code):
Effectively calls m.lock(). The behavior is undefined if m is not a recursive mutex and the current thread already owns m.
For the sake of completeness, there is a second constructor:
lock_guard( mutex_type& m, std::adopt_lock_t t );
which
Acquires ownership of the mutex m without attempting to lock it. The behavior is undefined if the current thread does not own m.
However, pop calls data.empty and this is the method of the private member, not the member function empty of threadsafe_stack. There is no problem in the code.
My Qt app uses QMutex and QMutexLocker to ensure thread-safety.
Does the mutex protect the data or scope of the function?
For example:
class Counter
{
public:
Counter() { *ptr; }
void setObject(MyClass *pr){ptr = pr;}
void increment() { QMutexLocker locker(&mutex); //dowork for ptr; }
void decrement() { QMutexLocker locker(&mutex); //dowork for pointer to MyClass, ptr; }
private:
mutable QMutex mutex;
MyClass *ptr;
};
//Thread...
Counter counter;
MyClass *mclass= new MyClass;
//setting... mclass
counter.setOjbect(mclass);
OtherClass oc; //This `OtherClass` also works for mclass same as the value of Counter.
oc.setObject(mclass); //Counter and OtherClass work for mclass.
//Mutex protect mclass data?
The pointer to MyClass could be used in some other class.
Does QMutexLocker protect the data for ptr or protect only accessing function increment and decrement from the multiple calling?
How can I protect data at ptr?
Mutual exclusion is ensured for all threads using the same QMutex instance e.g. it protects data. So another class cannot synchronize its access to MyClass because it cannot access the mutex (unless you can ensure two thread do not touch the same member fields).
You should guarantee that everyone who accesses MyClass instance uses the same mutex instance. This can be done by:
Moving the mutex to MyClass instance. This is what you most likely need.
Use a single global pool of mutexes and use MyClass instance address to select a mutex for it.
The latter way is shown below:
const std::size_t SIZE = 47; // prime numbers work better here
statuc QMutex g_mtx[SIZE];
QMutex &get_mutex(const void *ptr)
{
return g_mtx[std::uintptr_t(ptr) % SIZE];
}
To guard an instance of MyClass pointer to ptr you should use QMutexLocker(get_mutex(ptr)). This is useful if MyClass is a small object and it exists in large numbers, so keeping a separate mutex for each instance becomes a problem.
I have two classes similar to this:
class Foo {
public:
void bar() {
std::lock_guard<std::mutex> lock(m_mutex);
m_data.push_back('x');
}
private:
std::string m_data;
std::mutex m_mutex;
};
class Pool {
public:
static std::shared_ptr<Foo> Create(int index) {
std::lock_guard<std::mutex> lock(m_mutex);
if (m_pool.size() > 10) {
m_pool.erase(m_pool.begin());
}
std::shared_ptr<Foo>& ptr = m_pool[index];
if (!ptr) ptr.reset(new Foo);
return ptr;
}
private:
static std::mutex m_mutex;
static std::map<int, std::shared_ptr<Foo>> m_pool;
};
and several threads running this code:
void parallel_function(int index) {
// several threads can get the same index
std::shared_ptr<Foo> foo = Pool::Create(index);
foo->bar();
}
Cppreference says
All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object. If multiple threads of execution access the same shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur; the shared_ptr overloads of atomic functions can be used to prevent the data race.
Two questions:
Since Pool::Create always returns copies of the shared_ptr, I assume that the copy and destruction of each shared_ptr is thread-safe, either if it happens in m_pool.erase or at the end of parallel_function. Is this correct?
I call shared_ptr::operator->, which is a const member function, and the function Foo::bar is thread-safe. Is there a data race here?
To sum up my comments.
Yes, this is thread safe as you operate separate copies of shared_ptrs in different threads. Which is one of the few cases where passing copies of shared_ptrs is actually reasonable.
operator-> is a const member. So basically your code is fine as long as Foo::bar being race-free stands true (which it clearly is now).
I had a struct type:
struct MyStruct {
int field1;
int field2;
}
Then it became necessary to add a mutex to it to make it shared between threads:
struct MyStruct {
std::mutex _mutex;
int field1;
int field2;
}
But then the compiler (clang) give me these messages on lines where I assign one existing struct to variable of type MyStruct like MyStruct mystruct = p_MyStructMap->at(clientId);:
(1) error: object of type 'MyStruct' cannot be assigned because its copy assignment operator is implicitly deleted
(2) note: copy assignment operator of 'MyStruct' is implicitly deleted because field '_mutex' has a deleted copy assignment operator
std::mutex _mutex
^
(3) /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/mutex:129:12: note: function has been explicitly marked deleted here
mutex& operator=(const mutex&) = delete;
^
Please, help: How can I rewrite struct or may be the program logic to use mutexes for this struct?
Assuming that _mutex was added to protect the other fields from being simultaneously accessed, you will need to lock the mutex(s) during assignment, unless you can otherwise guarantee that multiple threads aren't accessing either side of the assignment expression:
x = y;
If any other thread is reading or writing to x simultaneously, you have a race without locking.
If any other thread is writing to y simultaneously, you have a race without locking.
If you do indeed need to lock, it is not quite as simple as locking both sides:
MyStruct& operator=(const MyStruct& o)
{
if (this != &o)
{
// WRONG! DO NOT DO THIS!!!
std::lock_guard<std::mutex> lhs_lk(_mutex);
std::lock_guard<std::mutex> rhs_lk(o._mutex);
field1 = o.field1;
field2 = o.field2;
}
return *this;
}
The reason you should not do this is imagine thread A does this:
x = y;
And simultaneously thread B does this:
y = x;
Now you have the potential for deadlock. Imagine thread A locks x._mutex, and then thread B locks y._mutex. Now both thread A and B will block trying to lock their o._mutex, and neither thread will ever succeed because it is waiting for the other thread to release it.
The correct formulation of the assignment operator can look like this:
MyStruct& operator=(const MyStruct& o)
{
if (this != &o)
{
std::lock(_mutex, o._mutex);
std::lock_guard<std::mutex> lhs_lk(_mutex, std::adopt_lock);
std::lock_guard<std::mutex> rhs_lk(o._mutex, std::adopt_lock);
field1 = o.field1;
field2 = o.field2;
}
return *this;
}
The job of std::lock(m1, m2, ...) is to lock all of the mutexes in some magical way that does not deadlock. For more detail than you probably want to know about how that is done, you can read Dining Philosophers Rebooted.
Now with _mutex and o._mutex locked, you simply need to make their unlocking exception safe by having the lock_guards adopt ownership of their mutexes. That is, they will no longer try to lock their mutex on construction, but they will still unlock them on destruction. The lock_guard constructors themselves throw nothing, so this is all exception safe.
Oh, you will also have to store _mutex as a mutable data member else you won't be able to lock and unlock it on the rhs.
In C++14 a potential optimization is available if you want to try it: You can "write-lock" this->_mutex and "read-lock" o._mutex. This would allow multiple threads to simultaneously assign from a common rhs if no threads are assigning to that rhs. In order to do that you need to have MyStruct store a std::shared_timed_mutex instead of a std::mutex:
#include <mutex>
#include <shared_mutex>
struct MyStruct
{
using MutexType = std::shared_timed_mutex;
using ReadLock = std::shared_lock<MutexType>;
using WriteLock = std::unique_lock<MutexType>;
mutable MutexType _mutex;
int field1;
int field2;
MyStruct& operator=(const MyStruct& o)
{
if (this != &o)
{
WriteLock lhs_lk(_mutex, std::defer_lock);
ReadLock rhs_lk(o._mutex, std::defer_lock);
std::lock(lhs_lk, rhs_lk);
field1 = o.field1;
field2 = o.field2;
}
return *this;
}
};
This is similar to as before except that we need to change the type of the mutex, and now the lhs locks with unique_lock (which write-locks the lhs mutex) and the rhs locks with shared_lock (which read-locks the rhs mutex). Here we also use std::defer_lock to construct the locks but to tell the locks that the mutex isn't locked yet, and don't lock on construction. And then our old friend std::lock(m1, m2) is used to tell both locks to lock at the same time without deadlock. Yes, std::lock works with both mutex and lock types. Anything that has member lock(), try_lock(), and unlock(), will work with std::lock(m1, m2, ...).
Note, the C++14 technique isn't definitely an optimization. You will have to measure to confirm or deny that it is. For something as simple as MyStruct it probably isn't an optimization, except perhaps for some special usage patterns. The C++11 technique with std::mutex continues to be a valuable tool in the toolbox, even in C++14.
For ease in switching back and fourth between the mutex and shared_timed_mutex, this latest example makes use of type aliases, which can be easily changed. One only has to change two lines to switch back to mutex:
using MutexType = std::shared_timed_mutex;
using ReadLock = std::sharedunique_lock<MutexType>;
using WriteLock = std::unique_lock<MutexType>;
std::mutex variables/members cannot be assigned, therefore, you get the error.
Try something like this:
struct MyStruct {
std::mutex _mutex;
int field1;
int field2;
MyStruct &operator=(const MyStruct &o) {
field1=o.field1;
field2=o.field2;
return *this;
}
};
However, this will not lock the mutex during the assignment. Depending on the context you may need to add locking inside the assignment operator or in the invoking function.
The straightforward way to make a class threadsafe is to add a mutex attribute and lock the mutex in the accessor methods
class cMyClass {
boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};
The problem is that this makes the class non-copyable.
I can make things work by making the mutex a static. However, this means that every instance of the class blocks when any other instance is being accessed, because they all share the same mutex.
I wonder if there is a better way?
My conclusion is that there is no better way. Making a class thread-safe with private static mutex attribute is ‘best’: - it is simple, it works, and it hides the awkward details.
class cMyClass {
static boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};
The disadvantage is that all instances of the class share the same mutex and so block each other unnecessarily. This cannot be cured by making the mutex attribute non-static ( so giving each instance its own mutex ) because the complexities of copying and assignment are nightmarish, if done properly.
The individual mutexes, if required, must be managed by an external non-copyable singleton with links established to each instance when created.
Thanks for all the responses.
Several people have mentioned writing my own copy constructor and assignment operator. I tried this. The problem is that my real class has many attributes which are always changing during development. Maintaining both the copy constructor and assignmet operator is tedious and error-prone, with errors creating hard to find bugs. Letting the compiler generate these for complex class is an enormous time saver and bug reducer.
Many responses are concerned about making the copy constructor and assignment operator thread-safe. This requirement adds even more complexity to the whole thing! Luckily for me, I do not need it since all the copying is done during set-up in a single thread.
I now think that the best approach would be to build a tiny class to hold just a mutex and the critical attributes. Then I can write a small copy constructor and assignment operator for the critical class and leave the compiler to look after all the other attributes in the main class.
class cSafe {
boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
(copy constructor)
(assignment op )
};
class cMyClass {
cSafe S;
( ... other attributes ... )
public:
cSomeClass getA() {
return S.getA();
}
};
You can define your own copy constructor (and copy assignment operator). The copy constructor would probably look something like this:
cMyClass(const cMyClass& x) : A(x.getA()) { }
Note that getA() would need to be const-qualified for this to work, which means the mutex would need to be mutable; you could make the parameter a non-const reference, but then you can't copy temporary objects, which usually isn't desirable.
Also, consider that it isn't always a good idea to perform locking at such a low level: if you lock the mutex in the accessor and the mutator functions, you lose a lot of functionality. For example, you can't perform a compare-and-swap because you can't get and set the member variable with a single lock of the mutex, and if you have multiple data members controlled by the mutex, you can't access more than one of them with the mutex locked.
As simple as the question might be, getting it right is not so simple. For starters we can work the easy copy constructor:
// almost pseudo code, mutex/lock/data types are synthetic
class test {
mutable mutex m;
data d;
public:
test( test const & rhs ) {
lock l(m); // Lock the rhs to avoid race conditions,
// no need to lock this object.
d = rhs.d; // perform the copy, data might be many members
}
};
Now creating an assignment operator is more complex. The first thing that comes to mind is just doing the same, but in this case locking both the lhs and rhs:
class test { // wrong
mutable mutex m;
data d;
public:
test( test const & );
test& operator=( test const & rhs ) {
lock l1( m );
lock l2( rhs.m );
d = rhs.d;
return *this;
}
};
Simple enough, and wrong. While we are guaranteeing single threaded access to the objects (both) during the operation, and thus we get no race conditions, we have a potential deadlock:
test a, b;
// thr1 // thr2
void foo() { void bar() {
a = b; b = a;
} }
And that is not the only potential deadlock, the code is not safe for self assignment (most mutex are not recursive, and trying to lock the same mutex twice will block the thread). The simple thing to solve is the self assignment:
test& test::operator=( test const & rhs ) {
if ( this == &rhs ) return *this; // nothing to do
// same (invalid) code here
}
For the other part of the problem you need to enforce an order in how the mutexes are acquired. That could be handled in different ways (storing a unique identifier per object an comparing...)
test & test::operator=( test const & rhs ) {
mutex *first, *second;
if ( unique_id(*this) < unique_id(rhs ) {
first = &m;
second = &rhs.m;
} else {
first = &rhs.m;
second = &rhs.m;
}
lock l1( *first );
lock l2( *second );
d = rhs.d;
}
The specific order is not as important as the fact that you need to ensure the same order in all uses, or else you will potentially deadlock the threads. As this is quite common, some libraries (including the upcoming c++ standard) have specific support for it:
class test {
mutable std::mutex m;
data d;
public:
test( const test & );
test& operator=( test const & rhs ) {
if ( this == &rhs ) return *this; // avoid self deadlock
std::lock( m, rhs.m ); // acquire both mutexes or wait
std::lock_guard<std::mutex> l1( m, std::adopt_lock ); // use RAII to release locks
std::lock_guard<std::mutex> l2( rhs.m, std::adopt_lock );
d = rhs.d;
return *this;
}
};
The std::lock function will acquire all locks passed in as argument and it ensures that the order of acquisition is the same, ensuring that if all code that needs to acquire these two mutexes does so by means of std::lock there will be no deadlock. (You can still deadlock by manually locking them somewhere else separately). The next two lines store the locks in objects implementing RAII so that if the assignment operation fails (exception is thrown) the locks are released.
That can be spelled differently by using std::unique_lock instead of std::lock_guard:
std::unique_lock<std::mutex> l1( m, std::defer_lock ); // store in RAII, but do not lock
std::unique_lock<std::mutex> l2( rhs.m, std::defer_lock );
std::lock( l1, l2 ); // acquire the locks
I just thought of a different much simpler approach that I am sketching here. The semantics are slightly different, but may be enough for many applications:
test& test::operator=( test copy ) // pass by value!
{
lock l(m);
swap( d, copy.d ); // swap is not thread safe
return *this;
}
}
There is a semantic difference in both approaches, as the one with copy-and-swap idiom has a potential race condition (that might or might not affect your application, but that you should be aware of). Since both locks are never held at once, the objects may change between the time the first lock is released (copy of the argument completes) and the second lock is acquired inside operator=.
For an example of how this might fail, consider that data is an integer and that you have two objects initialized with the same integer value. One thread acquires both locks and increments the values, while another thread copies one of the objects into the other:
test a(0), b(0); // ommited constructor that initializes the ints to the value
// Thr1
void loop() { // [1]
while (true) {
std::unique_lock<std::mutex> la( a.m, std::defer_lock );
std::unique_lock<std::mutex> lb( b.m, std::defer_lock );
std::lock( la, lb );
++a.d;
++b.d;
}
}
// Thr1
void loop2() {
while (true) {
a = b; // [2]
}
}
// [1] for the sake of simplicity, assume that this is a friend
// and has access to members
With the implementations of operator= that perform simultaneous locks on both objects, you can assert at any one given time (doing it thread safely by acquiring both locks) that a and b are the same, which seems to be expected by a cursory read of the code. That does not hold if operator= is implemented in terms of the copy-and-swap idiom. The issue is that in the line marked as [2], b is locked and copied into a temporary, then the lock is released. The first thread can then acquire both locks at once, and increment both a and b before a is locked by the second thread in [2]. Then a is overwritten with the value that b had before the increment.
The simple fact is that you cannot make a class thread safe by spewing mutexes at the problem. The reason that you can't make this work is because it doesn't work, not because you're doing this technique wrong. This is what everyone noticed when multithreading first came and started slaughtering COW string implementations.
Thread design occurs at the application level, not on a per-class basis. Only specific resource management classes should have thread-safety on this level- and for them you need to write explicit copy constructors/assignment operators anyway.