Professional C__ - Marc Gregoire [396]
class MyClass
{
public:
void init() {cout << "Init" << endl;}
};
MyClass var;
bool initialized = false;
mutex mut;
void func()
{
if (!initialized) {
unique_lock if (!initialized) { var.init(); initialized = true; } } cout << "OK" << endl; } int main() { cout.sync_with_stdio(true); // Make sure cout is thread-safe vector for (int i = 0; i < 5; ++i) threads.push_back(thread{func}); for (auto& t : threads) t.join(); return 0; } Code snippet from mutex\double_checked_locking.cpp The output of this program is as follows: Init OK OK OK OK OK This output clearly shows that only one thread has initialized the MyClass instance. CONDITION VARIABLES You need to include the std::condition_variable: A condition variable that can only wait on a unique_lock std::condition_variable_any: A condition variable that can wait on any kind of object, including custom lock types. The condition_variable class supports the following methods: notify_one(); Wake up one of the threads waiting on this condition variable. This is similar to an auto-reset event in Windows. notify_all(); Wake up all threads waiting on this condition variable. wait(unique_lock The thread calling wait() should already have acquired a lock on lk. The effect of calling wait() is that it will atomically call lk.unlock() and then block the thread, waiting for a notification. When the thread is unblocked by a notify_one() or notify_all() call in another thread, the function will call lk.lock() again, possibly blocking on the lock and then returns. wait_for(unique_lock const chrono::duration Similar to the previous wait() method, except that the thread will be unblocked by a notify_one() call, a notify_all() call, or when the given timeout has expired. wait_until(unique_lock const chrono::time_point Similar to the previous wait() method, except that the thread will be unblocked by a notify_one() call, a notify_all() call, or when the system time passes the given absolute time. There are also versions of wait(), wait_for(), and wait_until() that accept an extra predicate parameter. For example, wait() accepting an extra predicate is equivalent to: while (!predicate()) wait(lk); The condition_variable_any class supports the same methods as the condition_variable class except that it accepts any kind of Lock class instead of only a unique_lock Condition variables can, for example, be used for background threads processing items from a queue. You can define a queue in which you insert items to be processed. A background thread waits until there are items in the queue. When an item is inserted into the queue, the thread wakes up, processes the item, and goes back to sleep, waiting for the next item. Suppose you have the following queue: std::queue
Condition variables allow a thread to block until a certain condition is set by another thread or until the system time reaches a specified time. They allow for explicit inter-thread communication. If you are familiar with multithreaded programming using the Win32 API, you can compare condition variables with event objects in Windows.