I have a resource storing object that lives in a multithread application. To (hopefully) ensure thread-safety I lock a mutex everytime I want to access a resource or insert a new one. For example, to insert a new resource:
void ResourceManager::insertResource(const std::string& id)
{
// create the object with such ID
Resource res = Resource(id);
// ... more code on res
// lock the mutex to insert the resource
std::lock_guard<std::mutex> guard(mResourcesMutex);
// insert the resource in a STL container
mResources.insert(ResourceContainer::value_type(id, res));
// ... more code that does not require the mutex lock
}
I want to lock_guard to be minimally scoped so its destructor is called as soon as possible and other threads can access the resources. In particular, I'd like to unlock the mutex after the mResources.insert(...) statement.
I thought about scoping the lock_guard using a naive if-statement:
if(true)
{
std::lock_guard<std::mutex> guard(mResourceMutex);
mResources.insert(ResourceContainer::value_type(id, res);
}
but I don't know if its working. I find it hard to check if this is scoping the lock_guard right or if, on the other hand, the compiler just thinks I'm crazy and its optimizing the code taking out the if-statement.
My questions are:
Is this working?
Is it worth it? Will I notice a performance hit?
Are there any better alternatives?
Yes it works. As soon as you exit the scope, the objects local to that scope will be immediately destroyed.
Yes it is worth it, especially in cases like your example (reducing the lifetime of an object to ensure a resource is released early -- but you can also use it just to reduce the scope of a temporary identifier and make it inaccessible after that, even though this use is a bit less interesting than your example).
Yes there is a (slightly) better alternative: just use braces without the if clause:
.
{
std::lock_guard<std::mutex> guard(mResourceMutex);
mResources.insert(ResourceContainer::value_type(id, res);
}
A proper compiler will be able to optimize out the if (true) so the generated code will be identical, but the braces alone are much cleaner from a style point of view. Additionally the braces alone are a well known and immediately recognizable idiom, while your if (true) isn't and makes the reader wonder (even if briefly) "what is the purpose of that if? Oh wait, right, it's the usual scope-limiting idiom...".
Why you use if(true)?
You can simply use block scope
{
std::lock_guard<std::mutex> guard(mResourceMutex);
mResources.insert(ResourceContainer::value_type(id, res);
}
Related
Does is make sense to do something like putting a std::lock_guard in an extra scope so that the locking period is as short as possible?
Pseudo code:
// all used variables beside the lock_guard are created and initialized somewhere else
...// do something
{ // open new scope
std::lock_guard<std::mutex> lock(mut);
shared_var = newValue;
} // close the scope
... // do some other stuff (that might take longer)
Are there more advantages besides having a short lock duration?
What might be negative side effects?
Yes, it certainly makes sense to limit the scope of lock guards to be as short as possible, but not shorter.
The longer you hold a lock, the more likely it is that a thread will block waiting for that lock, which impacts performance as is thus usually considered a bad thing.
However, you must make sure that the program is still correct and that the lock is held at all times when it must be, i.e. when the shared resource protected by the lock is accessed or modified.
There may be one more point to consider (I do not have enough practical experience here to speak with certainty). Locking/releasing a mutex can potentially be an operation with nontrivial performance costs itself. Therefore, it may turn out that keeping a lock for a slightly longer period instead of unlocking & re-locking it several times in the course of one operation can actually improve overall performace. This is something which profiling could show you.
There might be a disadvantage: you cannot protect initializations this way. For example:
{
std::lock_guard<std::mutex> lock(mut);
Some_resource var{shared_var};
} // oops! var is lost
you have to use assignment like this:
Some_resource var;
{
std::lock_guard<std::mutex> lock(mut);
var = shared_Var;
}
which may be suboptimal for some types, for which default initialization followed by assignment is less efficient than directly initializing. Moreover, in some situations, you cannot change the variable after initialization. (e.g. const variables)
user32434999 pointed out this solution:
// use an immediately-invoked temporary lambda
Some_resource var {
[&] {
std::lock_guard<std::mutex> lock(mut);
return shared_var;
} () // parentheses for invoke
};
This way, you can protect the retrieval process, but the initialization itself is still not guarded.
Yes, it makes sense.
There are no other advantages, and there are no side-effects (it is a good way to write it).
An even better way, is to extract it into a private member function (if you have an operation that is synchronized this way, you might as well give the operation its own name):
{
// all used variables beside the lock_guard are created and initialized somewhere else
...// do something
set_var(new_value);
... // do some other stuff (that might take longer)
}
void your_class::set_value(int new_value)
{
std::lock_guard<std::mutex> lock(mut);
shared_var = new_value;
}
Using an extra scope specifically to limit the lifetime of an std::lock_guard object is indeed good practice. As the other answers point out, locking your mutex for the shortest period of time will reduce the chances that another thread will block on the mutex.
I see one more point that was not mentioned in the other answers: transactional operations. Let's use the classical example of a money transfer between two bank accounts. For your banking program to be correct, the modification of the two bank account's balance must be done without unlocking the mutex in between. Otherwise, it would be possible for another thread to lock the mutex while the program is in a weird state where only one of the accounts was credited/debited while the other account's balance was untouched!
With this in mind, it is not enough to ensure that the mutex is locked when each shared resource is modified. Sometimes, you must keep the mutex locked for a period of time spanning the modification of all the shared resources that form a transaction.
EDIT:
If for some reason keeping the mutex locked for the whole duration of the transaction is not acceptable, you can use the following algorithm:
1. Lock mutex, read input data, unlock mutex.
2. Perform all needed computations, save results locally.
3. Lock mutex, check that input data has not changed, perform the transaction with readily available results, unlock the mutex.
If the input data has changed during the execution of step 2, throw away the results and start over with the fresh input data.
I don't see the reason to do it.
If you do something so simple as "set one variable" - use atomic<> and you don't need mutex and lock at all. If you do something complicated - extract this code into new function and use lock in its first line.
I'm using boost to start a thread and the thread function is a member function of my class just like this:
class MyClass {
public:
void ThreadFunc();
void StartThread() {
worker_thread_ = boost::shared_ptr<boost::thread>(
new boost::thread(boost::bind(&MyClass::ThreadFunc, this)));
}
};
I will access some member variables in ThreadFunc:
while (!stop) {
Sleep(1000); // here will be some block operations
auto it = this->list.begin();
if (it != this->list.end())
...
}
I can not wait forever for thread return, so I set timeout:
stop = true;
worker_thread_->interrupt();
worker_thread_->timed_join(boost::posix_time::milliseconds(timeout_ms));
After timeout, I will delete this MyClass pointer. Here will be a problem, the ThreadFunc hasn't return, it will have chances to access this and its member variables. In my case, the iterator will be invalid and it != this->list.end() will be true, so my program will crash if using invalid iterator.
My question is how to avoid it ? Or how to check whether this is valid or member variables is valid ? Or could I set some flags to tell ThreadFunc the destructor has been called ?
There are a lot of possible solutions. One is to use a shared_ptr to the class and let the thread hold its own shared_ptr to the class. That way, the object will automatically get destroyed only when both threads are done with it.
How about you create a stopProcessing flag (make it atomic) as a member of MyClass and in your ThreadFunc method check at each cycle if this flag is set?
[EDIT: making clearer the answer]
There a two orthogonal problems:
stopping the processing (I lost my patience, stop now please). This can be arranged by setting a flag into MyClass and make ThreadFunc checking it as often as reasonable possible
deallocation of resources. This is best by using RAII - one example being the use of shared_ptr
Better keep them as separate concerns.
Combining them in a single operation may be possible, but risky.
E.g. if using shared_ptr, the once the joining thread decided "I had enough", it simply goes out of the block which keeps its "copy" of shared_ptr, thus the shared_ptr::use_count gets decremented. The thread function may notice this and decide to interpret it as an "caller had enough" and cut short the processing.However, this implies that, in the future releases, nobody else (but the two threads) may acquire a shared_ptr, otherwise the "contract" of 'decremented use_count means abort' is broken.
(a use_count==1 condition may still be usable - interpretation "Only me, the processing thread, seems to be interested in the results; no consumer for them, better abort the work").
I'm not quite sure why std::unique_lock<std::mutex> is useful over just using a normal lock. An example in the code I'm looking at is:
{//aquire lock
std::unique_lock<std::mutex> lock(queue_mutex);
//add task
tasks.push_back(std::function<void()>(f));
}//release lock
why would this preferred over
queue_mutex.lock();
//add task
//...
queue_mutex.unlock();
do these snippets of code accomplish the same thing?
[Do] these snippets of code accomplish the same thing?
No.
The first one will release the lock at the end of the block, no matter what the block is. The second will not release the lock at the end if the critical section is exited with a break, continue, return, goto, exception, or any other kind of non-local jump that I'm forgetting about.
The use of unique_lock offers resiliency in the face of changes and errors.
If you change the flow to add intermediate "jumps" (return for example)
If an exception is thrown
...
in any case, the lock is automatically released.
On the other hand, if you attempt to do it manually, you may miss a case. And even if you don't right now, a later edit might.
Note: this is a usual idiom in C++, referred to as SBRM (Scoped Bound Resources Management) where you tie down a clean-up action to stack unwinding so you are assured that, unless crash/ungraceful exit, it is executed.
It also shows off RAII (Resources Acquisition is Initialization) since the very construction of unique_lock acquires the resource (here the mutex). Despite its name, this acronym is also colloquially used to refer to deterministic release at destruction time, which covers a broader scope than SBRM since it refers to all kind of deterministic releases, not only those based on stack unwinding.
I have an unordered map which stores a pointer of objects. I am not sure whether I am doing the correct thing to maintain the thread safety.
typedef std::unordered_map<string, classA*>MAP1;
MAP1 map1;
pthread_mutex_lock(&mutexA)
if(map1.find(id) != map1.end())
{
pthread_mutex_unlock(&mutexA); //already exist, not adding items
}
else
{
classA* obj1 = new classA;
map1[id] = obj1;
obj1->obtainMutex(); //Should I create a mutex for each object so that I could obtain mutex when I am going to update fields for obj1?
pthread_mutex_unlock(&mutexA); //release mutex for unordered_map so that other threads could access other object
obj1->field1 = 1;
performOperation(obj1); //takes some time
obj1->releaseMutex(); //release mutex after updating obj1
}
Several thoughts.
If you do have one mutex per stored object, then you should try to create that mutex in the constructor for the stored object. In other words, to maintain encapsulation, you should avoid having external code manipulate that mutex. I would convert "field1" into a setter "SetField1" that handles the mutex internally.
Next, I agree with the comment that you could move pthread_mutex_unlock(&mutexA); to occur before obj1->obtainMutex();
Finally, I don't think you need obtainMutex at all. Your code looks as if only one thread will ever be allowed to create an object, and therefore only one thread will manipulate the contents during object creation. So if I consider only what little code you've shown here, it does not seem that mutex-per-object is needed at all.
One problem I see with the code is that it will lead to problems especially when exceptions occur.
obj1->obtainMutex(); //Should I create a mutex for each object so that I could obtain mutex when I am going to update fields for obj1?
pthread_mutex_unlock(&mutexA); //release mutex for unordered_map so that other threads could access other object
obj1->field1 = 1;
performOperation(obj1);
If performOperation throws an exception then obj1->releaseMutex(); will never get called thus leaving the object locked and potentially leading to deadlocks sometime in the future.
And even if you do not use exceptions yourself some library code you use in performOperation might. Or you might mistakenly sometime in the future insert a return and forget to unlock all owned locks before and so on...
The same goes for the pthread_mutex_lock and pthread_mutex_unlock calls.
I would recommend using RAII for locking / unlocking.
I.e. the code could look like this:
typedef std::unordered_map<string, classA*>MAP1;
MAP1 map1;
Lock mapLock(&mutexA); //automatci variable. The destructor of the Lock class
//automatically calls pthread_mutex_unlock in its destructor if it "owns" the
//mutex
if(map1.find(id) == map1.end())
{
classA* obj1 = new classA;
map1[id] = obj1;
Lock objLock(obj);
mapLock.release(); //we explicitly release mapLock here
obj1->field1 = 1;
performOperation(obj1); //takes some time
}
I.e. for a reference for some minimalistic RAAI threading support please refer to "Modern C++ design: generic programming and design patterns applied" by Andrei Alexandrescu (see here). Other resources also exist (here)
I will try to describe in the end one other problem I see with the code. More exactly, the problem I see with having the obtainMutex and releaseMutex as methods and calling them explicitly. Let's imagine thread 1 locks the map, creates an object calls obtainMutex and unlocks the map. Another thread (lets call it Thread 2) gets scheduled for execution locks the map obtains an iterator to the map1[id] of the object and calls releaseMutex() on the pObject (i.e. let's say due to a bug the code does not attempt to call obtainMutex first). Now Thread 1 gets scheduled and calls at some point releaseMutex() also. So the object got locked once but released twice. What I am trying to say is that it's going to be hard work making sure the calls are always correctly paired in the face of exceptions, potential early returns that do not unlock and incorrect usage of the object locking interface. Also Thread 2 might just delete the pObject it obtained from the map and erase it from the map. thread 1 will then go on an work with an already deleted object.
When used judiciously RAII would make the code simpler to understand (even shorter if you compare our versions) and also help a lot with some of the problems I enumerated above.
Thought of combining my comments into an answer:
1) When you are adding an entry, and therefore are modifying the container, you should not allow read access from other threads, as the container may be in a transition between legal states. Complementary, you should not modify the container when other threads are reading it. This calls for the use of read-write lock. The pseudo-code is something like:
set read lock
search container
if found
release read lock
operate on the found object
else
set write lock
release read lock
add entry
release write lock
endif
(it's been some time since I've done multi-threaded programming, so I may be rusty on details)
2) When I worked on MSVC some years ago we used the multi-threaded (i.e. thread-safe) version of the standard libraries. It could save you all this trouble. Didn't bother (yet) to check if thread-safe std exists also on gcc/Linux.
I have a class that is accessed from multiple threads. Both of its getter and setter functions are guarded with locks.
Are the locks for the getter functions really needed? If so, why?
class foo {
public:
void setCount (int count) {
boost::lock_guard<boost::mutex> lg(mutex_);
count_ = count;
}
int count () {
boost::lock_guard<boost::mutex> lg(mutex_); // mutex needed?
return count_;
}
private:
boost::mutex mutex_;
int count_;
};
The only way you can get around having the lock is if you can convince yourself that the system will transfer the guarded variable atomicly in all cases. If you can't be sure of that for one reason or another, then you'll need the mutex.
For a simple type like an int, you may be able to convince yourself this is true, depending on architecture, and assuming that it's properly aligned for single-instruction transfer. For any type that's more complicated than this, you're going to have to have the lock.
If you don't have a mutex around the getter, and a thread is reading it while another thread is writing it, you'll get funny results.
Is the mutex really only protecting a single int? It makes a difference -- if it is a more complex datatype you definitely need locking.
But if it is just an int, and you are sure that int is an atomic type (i.e., the processor will not have to do two separate memory reads to load the int into a register), and you have benchmarked the performance and determined you need better performance, then you may consider dropping the lock from both the getter and the setter. If you do that, make sure to qualify the int as volatile. And write a comment explaining why you do not have mutex protection, and under what conditions you would need it if the class changes.
Also, beware that you don't have code like this:
void func(foo &f) {
int temp = f.count();
++temp;
f.setCount(temp);
}
That is not threadsafe, regardless of whether you use a mutex or not. If you need to do something like that, the mutex protection has to be outside the setter/getter functions.
The synchronization concern is already covered in other answers (specifically David Schwartz's).
There's another concern I don't see addressed, though: this is usually a bad design.
Consider David's example code, assuming we have a correctly-synchronized version of foo
{
foo j;
some_func(j);
while (j.count() == 0)
{
// do we still expect (j.count() == 0) here?
bar();
}
}
The code suggests that the while condition still holds in the body. That's how single-threaded code works, after all.
But of course, even if we correctly synchronize the implementation of a getter, the setter can still be called from another thread, between our while condition succeeding and the first instruction of the loop body executing.
So, if any logic in the loop body can't depend on the condition being true, what was the point of testing it?
Sometimes it makes perfect sense, such as
while (foo.shouldKeepRunning())
{
// foo event loop or something
}
where it's OK if our shouldKeepRunning state changes during the loop body, because we only need to test it periodically. However, if you're going to do something with count, you need a longer-lived lock, and an interface to support it:
{
auto guard = j.lock_guard();
while (j.count(guard) == 0) // prove to count that we're locked
{
// now we _know_ count is zero in the body
// (but bar should release and re-acquire the lock or that can never change)
bar(j);
}
} // guard goes out of scope and unlocks
in you case probably not, if your cpu is 32 bit, however if count is a complex object or cpu needs more than one instruction to update its value, then yes
The lock is necessary to serialize access to shared resource. In your specific case you might get away with just atomic integer operations but in general, for larger objects that require more then one bus transaction, you do need locks to guarantee that reader always sees a consistent object.
It depends on the exact implementation of the object being locked. However, in general you do not want someone modifying (setting?) an object while someone else is in the process of reading (getting?) it. The easiest way to prevent that is to have a reader lock it.
In more complicated setups the lock will be implemented in such a way that any number of folks can read at once, but nobody can write to it while anyone is reading, and nobody can read while a write is going on.
They are really needed.
Imagine if you have an instance of class foo that's completely local to some piece of code. And you have something like this:
{
foo j;
some_func(j); // this stashes a reference to j where another thread can find it
while (j.count() == 0)
bar();
}
Suppose the optimizer looks carefully at the code to bar and sees that it can't possibly modify j.count_. This allows the optimizer to rewrite the code as follows:
{
foo j;
some_func(j); // this stashes a reference to j where another thread can find it
if (j.count() == 0)
{
while (1)
bar();
}
}
Clearly this is a disaster. Another thread might call j.setCount(5) and the thread wouldn't exit to loop.
The compiler can prove that bar can't modify the return value of j.count(). If it was required to assume that another thread could modify every memory value it accesses, it could never stash anything in a register ever, which would clearly be an untenable situation.
So, yes, the lock is needed. Alternatively, you need to use some other construct that provides similar guarantees.
Do not ever write code that relies on compilers not being able to make any optimization that they are permitted to make unless you really have no other practical choice. I have seen this cause a lot of pain over the many years I've been programming. Optimizers today can do things that would have been considered absurdly implausible a decade ago and lots of code lasts longer than you expect.