Online Book Reader

Home Category

Professional C__ - Marc Gregoire [394]

By Root 1374 0
has obtained a lock on the referenced mutex and will manage this lock.

unique_lock(mutex_type& m, adopt_lock_t);

A constructor accepting a reference to a mutex and an absolute time. The constructor tries to obtain a lock until the system time passes the given absolute time. The Chrono library is discussed in Chapter 16.

template

unique_lock(mutex_type& m, const chrono::time_point& abs_time);

A constructor accepting a reference to a mutex and a relative time. The constructor tries to get a lock on the mutex with the given relative timeout.

template

unique_lock(mutex_type& m, const chrono::duration& rel_time);

The unique_lock class also has the following methods: lock(), try_lock(), try_lock_for() and try_lock_until(), which behave as explained in the section on timed mutex classes earlier in this chapter. You can use the owns_lock() method to see if the lock has been acquired.

C++11 also has support for obtaining locks on multiple mutex objects at once. For this, you can use the generic lock() variadic template function. Variadic template functions are discussed in Chapter 20.

template void lock(L1&, L2&, L3&...);

This generic function locks all the mutex objects in order. If one of the mutex lock calls throws an exception, unlock() is called on all locks that have already been obtained.

There is also a generic try_lock() function:

template int try_lock(L1&, L2&, L3&...);

try_lock() tries to obtain a lock on all the given mutex objects by calling try_lock() on each of them in sequence. It returns -1 if all calls to try_lock() succeed. If any try_lock() fails, unlock() is called on all locks that have already been obtained, and the return value is the zero-based index of the parameter position of the mutex on which try_lock() failed.

When your threads need to acquire multiple locks at once, it is recommended to use the generic try_lock() or lock(), always using the same order for the mutex arguments. If you don’t use the same order for the mutex arguments, deadlocks might occur.

The following example demonstrates how to use the generic lock() function. The process() function first creates two locks, one for each mutex, and gives an instance of std::defer_lock_t as second argument to tell unique_lock not to acquire the lock during construction. The call to lock() will then acquire both locks:

mutex mut1;

mutex mut2;

void process()

{

unique_lock lock1(mut1, defer_lock_t());

unique_lock lock2(mut2, defer_lock_t());

lock(lock1, lock2);

// Locks acquired

}

int main()

{

process();

return 0;

}

Code snippet from mutex\multiple_locks.cpp

By always calling lock() in all threads with the lock1 and lock2 arguments in the same order, lock() will not cause any deadlocks. However, if you do call lock() from another thread, for example as follows, deadlocks might occur:

lock(lock2, lock1);

std::call_once

You can use std::call_once() in combination with std::once_flag to make sure a certain function or method is called exactly one time no matter how many threads try to call call_once().

Only one call_once() invocation will actually call the given function or method; this invocation is called the effective call_once() invocation. This effective invocation on a specific once_flag instance finishes before all subsequent call_once() invocations on the same once_flag instance. Other threads calling call_once() on the same once_flag instance will block until the effective call is finished. Figure 22-3 illustrates this with three threads. Thread 1 performs the effective call_once() invocation, Thread 2 blocks until the effective invocation is finished, and Thread 3 doesn’t block because the effective invocation from Thread 1 has already finished.

FIGURE 22-3

The following example demonstrates the use of call_once(). The example defines a class called Data, which has a dynamically allocated block of memory called mMemory. The mutable

Return Main Page Previous Page Next Page

®Online Book Reader