The standard library provides a mutex class, with the ability to manually lock and unlock it:
std::mutex m;
m.lock();
// ...
m.unlock();
However, the library apparently also recognizes that a common case is just to lock the mutex at some point, and unlock it when leaving a block. For this it provides std::lock_guard and std::unique_lock:
std::mutex m;
std::lock_guard<std::mutex> lock(m);
// ...
// Automatic unlock
I think a fairly common pattern for threads, is to create one (either as a stack variable, or a member), then join it before destructing it:
std::thread t(foo);
// ...
t.join();
It seems easy to write a thread_guard, which would take a thread (or a sequence of threads), and would just call join on its own destruction:
std::thread t(foo);
thread_guard<std::thread> g(t);
// ...
// Join automatically
Is there a standard-library class like it?
If not, is there some reason to avoid this?
This issue is discussed in Scott Meyer's book "Modern Effective c++"
The problem is that if there would be another default behavior (detach or join) would cause hard to find errors in case you forget that there is a implicit operation. So the actual default behavior on destruction is asserting if not explicitly joined or detached. And no "Guard" class is there also because of that reason.
If you always want to join it's safe to write such a class yourself. But when someone uses it and wants to detach people can forget that the destructor will implicitly join it. So that's the risk in writing such function.
As an alternative you can use a scope_guard by boost or the folly library (which I personally prefer more) and declare in the beginning explicitly your intention and it will be executed. Or you can write a policy based "Guard" class where you have to explicitly state what you want to do on destruction.
Related
Basically, the title is self-explanatory.
I use it in following way:
The code is in Objective-C++.
Objective-C classes make concurrent calls to different purpose functions.
I use std::mutex to lock and unlock std::vector<T> editing option across entire class, as C++ std containers are not thread safe.
Using lock_guard automatically unlocks the mutex again when it goes out of scope. That makes it impossible to forget to unlock it, when returning, or when an exception is thrown. You should always prefer to use lock_guard or unique_lock instead of using mutex::lock(). See http://kayari.org/cxx/antipatterns.html#locking-mutex
lock_guard is an example of an RAII or SBRM type.
The std::lock_guard is only used for two purposes:
Automate mutex unlock during destruction (no need to call .unlock()).
Allow simultaneous lock of multiple mutexes to overcome deadlock problem.
For the last use case you will need std::adopt_lock flag:
std::lock(mutex_one, mutex_two);
std::lock_guard<std::mutex> lockPurposeOne(mutex_one, std::adopt_lock);
std::lock_guard<std::mutex> lockPurposeTwo(mutex_two, std::adopt_lock);
On the other hand, you will need allocate yet another class instance for the guard every time you need to lock the mutex, as std::lock_guard has no member functions. If you need guard with unlocking functionality take a look at std::unique_lock class. You may also consider using std::shared_lock for parallel reading of your vector.
You may notice, that std::shared_lock class is commented in header files and will be only accessible with C++17. According to header file you can use std::shared_timed_mutex, but when you will try to build the app it will fail, as Apple had updated the header files, but not the libc++ itself.
So for Objective-C app it may be more convenient to use GCD, allocate a couple of queue for all your C++ containers at the same time and put semaphores where needed. Take a look at this excellent comparison.
#include<iostream>
#include<vector>
#include<thread>
#include<string>
using namespace std;
vector<string> s;
void add()
{
while(true)
{
getchar();
s.push_back("added");
}
}
void show()
{
while(true)
{
//cout<<"";
while(!s.empty())
{
cout<<(*s.begin())<<endl;
s.erase(s.begin());
}
}
}
int main()
{
thread one(add);
thread two(show);
one.join();
two.join();
}
In debug mode there is no such a problem. In release mode if the comment line is uncommented it works again. But with just like this, there is a problem. What is the problem?
std::vector (as any other std:: container) is not generally thread-safe. It means that concurrent modifying access to the same vector from multiple thread is generally not supported. What that means is that while you can call non-modifying functions of the vector from many threads at the same time (for instance, you can call begin() and end() with no problems), modification functions should have exclusive access to the vector object. To achieve this exclusivity, you need to use thread-synchronization primitives to 'signal' your intention to obtain exclusive access to the vector, perform your modification and than 'signal' that exclusive access is no longer need.
Note, this is not enough to perform that sort of routine when you modify (insert) data to the vector. You will also have to do the same dance when you read data from the vector, since modifications need exclusive access, and even the read will violate this exclusivity. The non-technical term I've used here, 'signalling', has a technical counterpart - it is called critical section. Here we say that you 'enter critical section' and 'leave critical section'.
There a more than one way to enter and leave critical section. The stapples of this are so-called mutexes, and they should be enough for your learning. Just keep in mind there are other ways as well, which you'll learn in the due course.
I have a multithreaded app that has to read some data often, and occasionally that data is updated. I have problems with writing by using unique_lock and problems with reading by using upgrade_lock
There is examples of my problems:
void unlock(){
test.stream = 0;
test.mtx.unlock();
}
void lock_mtx(int i){
boost::unique_lock<boost::shared_mutex> lock(test.mtx);
test.stream = i;
boost::this_thread::sleep_for(boost::chrono::milliseconds(10000));
unlock();
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
}
When I destruct lock , mutex is already unlocked by this thread, and sometimes it is locked by another thread, but destructor make it free again. After destruction of lock (in the first thread) third thread take mutex and I have two writers at the one moment
void lock_mtx(int i){
boost::upgrade_lock<boost::shared_mutex> lock(test.mtx);
read_from_locked();
boost::this_thread::sleep_for(boost::chrono::milliseconds(5000));
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
write_to_locked();
boost::this_thread::sleep_for(boost::chrono::milliseconds(10000));
}
The second problem, is that when some thread takes upgrade_lock, other threads can't read shared objects
Both of problems occur in MS VisualStudio 2013 and Windows8 x64
void lock_mtx(int i)
{
{
boost::unique_lock<boost::shared_mutex> lock(test.mtx);
test.stream = i;
boost::this_thread::sleep_for(boost::chrono::milliseconds(10000));
}
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
}
The purpose of unique_lock and lock_guard is to automatically unlock the mutex when it goes out of scope. This pattern is known as RAII.
Rule of thumb: Never manually call lock()/unlock() on your (Basic|Shared)Lockable objects. It's an antipattern because
It's extremely hard to get right (think of exception safety)
It usually indicates a code smell (locks being held across different method calls). If you even need this, consider making the RAII lock guard (lock_guard or unique_lock) a member of the containing class, or return the unique_lock so the caller has the option to explicitly adopt the lock, or to just let it be automatically released by the guard.
The new machine model of C++11 allows for multi-processor systems to work reliably, wrt. to reorganization of instructions.
As Meyers and Alexandrescu pointed out the "simple" Double-Checked Locking Pattern implementation is not safe in C++03
Singleton* Singleton::instance() {
if (pInstance == 0) { // 1st test
Lock lock;
if (pInstance == 0) { // 2nd test
pInstance = new Singleton;
}
}
return pInstance;
}
They showed in their article that no matter what you do as a programmer, in C++03 the compiler has too much freedom: It is allowed to reorder the instructions in a way that you can not be sure that you end up with only one instance of Singleton.
My question is now:
Do the restrictions/definitions of the new C++11 machine model now constrain the sequence of instructions, that the above code would always work with a C++11 compiler?
How does a safe C++11-Implementation of this Singleton pattern now looks like, when using the new library facilities (instead of the mock Lock here)?
If pInstance is a regular pointer, the code has a potential data race -- operations on pointers (or any builtin type, for that matter) are not guaranteed to be atomic (EDIT: or well-ordered)
If pInstance is an std::atomic<Singleton*> and Lock internally uses an std::mutex to achieve synchronization (for example, if Lock is actually std::lock_guard<std::mutex>), the code should be data race free.
Note that you need both explicit locking and an atomic pInstance to achieve proper synchronization.
Since static variable initialization is now guaranteed to be threadsafe, the Meyer's singleton should be threadsafe.
Singleton* Singleton::instance() {
static Singleton _instance;
return &_instance;
}
Now you need to address the main problem: there is a Singleton in your code.
EDIT: based on my comment below: This implementation has a major drawback when compared to the others. What happens if the compiler doesn't support this feature? The compiler will spit out thread unsafe code without even issuing a warning. The other solutions with locks will not even compile if the compiler doesn't support the new interfaces. This might be a good reason not to rely on this feature, even for things other than singletons.
C++11 doesn't change the meaning of that implementation of double-checked locking. If you want to make double-checked locking work you need to erect suitable memory barriers/fences.
Let's say I'm programming in a threading framework that does not have multiple-reader/single-writer mutexes. Can I implement their functionality with the following:
Create two mutexes: a recursive (lock counting) one for readers and a binary one for the writer.
Write:
acquire lock on binary mutex
wait until recursive mutex has lock count zero
actual write
release lock on binary mutex
Read:
acquire lock on binary mutex (so I know the writer is not active)
increment count of recursive mutex
release lock on binary mutex
actual read
decrement count of recursive mutex
This is not homework. I have no formal training in concurrent programming, and am trying to grasp the issues. If someone can point out a flaw, spell out the invariants or provide a better algorithm, I'd be very pleased. A good reference, either online or on dead trees, would also be appreciated.
The following is taken directly from The Art of Multiprocessor Programming which is a good book to learn about this stuff. There's actually 2 implementations presented: a simple version and a fair version. I'll go ahead and reproduce the fair version.
One of the requirements for this implementation is that you have a condition variable primitive. I'll try to figure out a way to remove it but that might take me a little while. Until then, this should still be better than nothing. Note that it's also possible to implement this primitive using only locks.
public class FifoReadWriteLock {
int readAcquires = 0, readReleases = 0;
boolean writer = false;
ReentrantLock lock;
Condition condition = lock.newCondition(); // This is the condition variable.
void readLock () {
lock.lock();
try {
while(writer)
condition.await();
readAcquires++;
}
finally {
lock.unlock();
}
}
void readUnlock () {
lock.lock();
try {
readReleases++;
if (readAcquires == readReleases)
condition.signalAll();
}
finally {
lock.unlock();
}
}
void writeLock () {
lock.lock();
try {
while (writer)
condition.await();
writer = true;
while (readAcquires != readReleases)
condition.await();
}
finally {
lock.unlock();
}
}
void writeUnlock() {
writer = false;
condition.signalAll();
}
}
First off, I simplified the code a little but the algorithm remains the same. There also happens to be an error in the book for this algorithm which is corrected in the errata. If you plan on reading the book, keep the errata close by or you'll end up being very confused (like me a few minutes ago when I was trying to re-understand the algorithm). Note that on the bright side, this is a good thing since it keeps you on your toes and that's a requirement when you're dealing with concurrency.
Next, while this may be a Java implementation, only use it as pseudo code. When doing the actual implementation you'll have to be carefull about the memory model of the language or you'll definitely end up with a headache. As an example, I think that the readAcquires and readReleases and writer variable all have to be declared as volatile in Java or the compiler is free to optimize them out of the loops. This is because in a strictly sequential programs there's no point in continuously looping on a variable that is never changed inside the loop. Note that my Java is a little rusty so I might be wrong. There's also another issue with integer overflow of the readReleases and readAcquires variables which is ignored in the algorithm.
One last note before I explain the algorithm. The condition variable is initialized using the lock. That means that when a thread calls condition.await(), it gives up its ownership of the lock. Once it's woken up by a call to condition.signalAll() the thread will resume once it has reacquired the lock.
Finally, here's how and why it works. The readReleases and readAcquires variables keep track of the number threads that have acquired and released the read lock. When these are equal, no thread has the read lock. The writer variable indicates that a thread is trying to acquire the write lock or it already has it.
The read lock part of the algorithm is fairly simple. When trying to lock, it first checks to see if a writer is holding the lock or is trying to acquire it. If so, it waits until the writer is done and then claims the lock for the readers by incrementing the readAcquires variable. When unlocking, a thread increases the readReleases variable and if there's no more readers, it notifies any writers that may be waiting.
The write lock part of the algorithm isn't much more complicated. To lock, a thread must first check whether any other writer is active. If they are, it has to wait until the other writer is done. It then indicates that it wants the lock by setting writer to true (note that it doesn't hold it yet). It then waits until there's no more readers before continuing. To unlock, it simply sets the variable writer to false and notifies any other threads that might be waiting.
This algorithm is fair because the readers can't block a writer indefinitely. Once a writer indicates that it wants to acquire the lock, no more readers can acquire the lock. After that the writer simply waits for the last remaining readers to finish up before continuing. Note that there's still the possibility of a writer indefinitely blocking another writer. That's a fairly rare case but the algorithm could be improved to take that into account.
So I re-read your question and realised that I partly (badly) answered it with the algorithm presented below. So here's my second attempt.
The algorithm, you described is fairly similar to the simple version presented in the book I mentionned. The only problem is that A) it's not fair and B) I'm not sure how you would implement wait until recursive mutex has lock count zero. For A), see above and for B), the book uses a single int to keep track of the readers and a condition variable to do the signalling.
You may want to prevent write starvation, to accomplish this you can either give preference to writes or make mutex fair.
ReadWriteLock Java's interface documentation says Writer preference is common,
ReentrantReadWriteLock class documentation says
This class does not impose a reader or writer preference ordering for lock access. However, it does support an optional fairness policy.
Note R..'s comment
Rather than locking and unlocking the binary mutex for reading, you
can just check the binary mutex state after incrementing the count on
the recursive mutex, and wait (spin/yield/futex_wait/whatever) if it's
locked until it becomes unlocked
Recommended reading:
Programming with POSIX Threads
Perl's RWLock
Java's ReadWriteLock documentation.