unique_lock 取代 lock_guard
- std::lock_guard 和 std::unique_lock 都能实现自动加锁与解锁功能。
- std::unique_lock 内部持有 mutex 的状态(locked,unlocked),因此比 lock_guard 使用更加灵活但同时更占用空间、速度更慢。
// unique_lock example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
std::mutex mtx; // mutex for critical section
void print_block (int n, char c)
{
// critical section (exclusive access to std::cout signaled by lifetime of lck):
std::unique_lock<std::mutex> lck (mtx);
for (int i=0; i<n; ++i) {
std::cout << c;
}
std::cout << '\n';
}
int main ()
{
std::thread th1 (print_block,50,'*');
std::thread th2 (print_block,50,'$');
th1.join();
th2.join();
return 0;
}
输出:
**************************************************
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
unique_lock 的属性参数
属性 | 描述 |
通过调用成员lock来锁定互斥对象 | |
try_lock | 通过调用成员try_lock尝试锁定互斥对象 |
defer_lock | unique_lock 对象不会在构造时自动锁定互斥对象,将其初始化未不拥有锁 |
adopt_lock | unique_lock对象不会在构造时锁定互斥对象,而是假定调用线程已经拥有互斥锁的所有权。 |
try_to_lock
std::unique_lock<std::mutex>lck (mutex,std::try_to_lock);
defer_lock
std::unique_lock<std::mutex>lck (mutex,std::defer_lock);
// ...
lck.lock();
// ...
lck.unlock();
// ...
lck.lock();
adopt_lock
mutex.lock();
// ......
std::unique_lock<std::mutex>lck (mutex,std::adopt_lock);
std::unique_lock 的成员函数
std::unique_lock::owns_lock()
bool owns_lock() const noexcept;
功能:拥有锁
- 返回对象是否拥有锁。
- 如果托管互斥对象以由 unique_lock 对象锁定,并且此后未解锁或释放,则返回 true。
- 在其它情况下,都返回 false。
- 这是
unique_lock :: operator bool
的别名。
参数
- 无
返回值
- 如果对象在托管互斥对象上拥有锁,则返回 true, 否则返回 false。
// unique_lock::operator= example
#include <iostream> // std::cout
#include <vector> // std::vector
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock, std::try_to_lock
std::mutex mtx; // mutex for critical section
void print_star () {
std::unique_lock<std::mutex> lck(mtx,std::try_to_lock);
// print '*' if successfully locked, 'x' otherwise:
if (lck.owns_lock())
std::cout << '*';
else
std::cout << 'x';
std::cout << '\n';
}
int main ()
{
std::vector<std::thread> threads;
for (int i=0; i<10; ++i)
threads.emplace_back(print_star);
for (auto& x: threads) x.join();
return 0;
}
输出:
*
*
*
*
*
*
*
*
*
*
std::unique_lock::lock()
template <class Mutex1, class Mutex2, class... Mutexes>
void lock (Mutex1& a, Mutex2& b, Mutexes&... cde);
功能:锁定多个互斥锁
- 锁定所有作为参数的对象,并在必要时阻塞调用线程。
- 该函数用一个未指定序列去调用他们的 lock, try_lock 和 unlock 成员锁定对象,以确保所有参数在返回时都被锁定(不产生任何死锁)。
- 如果该函数无法锁定所有对象(例如,由于内部调用之一引发了异常),则该函数会在失败之前首先解锁成功锁定的所有对象(如果有)。
参数
a, b, cde
- 尝试锁定的对象,Mutex1,Mutex2和Mutexes 应该是可以锁定的类型。
返回值
- 无
std::unique_lock::unlock()
void unlock();
功能:解锁互斥锁
- 调用托管互斥对象的成员解锁,并将拥有状态设置为 false。
- 如果在调用之前拥有状态为 false,则该函数将引发 system_error 异常。
返回值
- 无
// unique_lock::lock/unlock
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock, std::defer_lock
std::mutex mtx; // mutex for critical section
void print_thread_id (int id) {
std::unique_lock<std::mutex> lck (mtx,std::defer_lock);
// critical section (exclusive access to std::cout signaled by locking lck):
lck.lock();
std::cout << "thread #" << id << '\n';
lck.unlock();
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_thread_id,i+1);
for (auto& th : threads) th.join();
return 0;
}
输出:
thread #1
thread #2
thread #4
thread #3
thread #7
thread #5
thread #6
thread #10
thread #8
thread #9
std::unique_lock::try_lock()
template <class Mutex1, class Mutex2, class... Mutexes>
int try_lock (Mutex1& a, Mutex2& b, Mutexes&... cde);
功能:尝试去锁定多个对象
- 尝试使用其 try_lock 成员函数锁定所有作为参数传递的对象(非阻塞)。
- 该函数为每个参数(首先是a,然后是b,最后是cde中的其它参数,以相同的顺序)调用 try_lock 成员函数,直到所有调用都成功或者其中一个调用失败(通过返回错误或引发异常)。
- 如果函数由于调用失败而结束,则对 try_lock 调用成功的所有对象都将解锁,并且该函数返回锁定失败的对象的参数顺序号。不会对参数列表中的其余对象执行进一步的调用。
参数
a, b, cde
- 尝试锁定的对象,Mutex1,Mutex2和Mutexes 应该是可以锁定的类型。
返回值
- 如果函数成功锁定了所有对象,则返回 -1。
- 否则,该函数将返回未定锁定对象的索引(0表示a,1表示b)
// unique_lock::try_lock example
#include <iostream> // std::cout
#include <vector> // std::vector
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock, std::defer_lock
std::mutex mtx; // mutex for critical section
void print_star () {
std::unique_lock<std::mutex> lck(mtx,std::defer_lock);
// print '*' if successfully locked, 'x' otherwise:
if (lck.try_lock())
std::cout << '*';
else
std::cout << 'x';
std::cout << '\n';
}
int main ()
{
std::vector<std::thread> threads;
for (int i=0; i<10; ++i)
threads.emplace_back(print_star);
for (auto& x: threads) x.join();
return 0;
}
输出:
*
*
*
*
*
*
*
*
*
*
std::unique_lock::release()
mutex_type* release() noexcept;
功能:释放互斥锁
- 返回指向退管互斥对象的指针,从而释放对其的所有权。
- 调用之后, unique_lock 对象不再管理任何互斥对象(即,其状态与默认构造的状态相同)。
- 请注意,此函数不会锁定或解锁返回的互斥量。
参数
- 无
返回值
- 指向调用之前由 unique_lock 管理的互斥对象的指针。
// unique_lock::release example
#include <iostream> // std::cout
#include <vector> // std::vector
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
std::mutex mtx;
int count = 0;
void print_count_and_unlock (std::mutex* p_mtx) {
std::cout << "count: " << count << '\n';
p_mtx->unlock();
}
void task() {
std::unique_lock<std::mutex> lck(mtx);
++count;
print_count_and_unlock(lck.release());
}
int main ()
{
std::vector<std::thread> threads;
for (int i=0; i<10; ++i)
threads.emplace_back(task);
for (auto& x: threads) x.join();
return 0;
}
输出:
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
count: 7
count: 8
count: 9
count: 10
std::unique_lock::mutex
mutex_type* mutex() const noexcept;
功能:获取互斥量
- 返回指向托管互斥对象的指针。
- 请注意,unique_lock 不会释放对托管互斥量的所有权。即,如果它拥有互斥锁,则仍然负责在某个时刻释放锁(例如销毁它时)
参数
- 无
返回值
指向由 unique_lock 管理的互斥对象的指针。
// unique_lock::mutex example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock, std::defer_lock
class MyMutex : public std::mutex {
int _id;
public:
MyMutex (int id) : _id(id) {}
int id() {return _id;}
};
MyMutex mtx (101);
void print_ids (int id) {
std::unique_lock<MyMutex> lck (mtx);
std::cout << "thread #" << id << " locked mutex " << lck.mutex()->id() << '\n';
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_ids,i+1);
for (auto& th : threads) th.join();
return 0;
}
输出:
thread #1 locked mutex 101
thread #2 locked mutex 101
thread #3 locked mutex 101
thread #4 locked mutex 101
thread #7 locked mutex 101
thread #5 locked mutex 101
thread #10 locked mutex 101
thread #8 locked mutex 101
thread #9 locked mutex 101
thread #6 locked mutex 101
std::unique_lock::operator =
move (1)
unique_lock& operator= (unique_lock&& x) noexcept;
copy [deleted] (2)
unique_lock& operator= (const unique_lock&) = delete;
功能:移动赋值
- 用 x 中的一个替换托管的互斥对象,包括其拥有的状态。
- 如果对象在调用之前在其托管互斥对象上拥有锁,则在替换之前将调用其unlock成员。
- x 保持与默认构造相同的状态(指没有托管对象)。
- unique_lock 对象无法赋值。
参数
x
- 另一个 unique_lock 对象。
返回值
- *this。
// unique_lock::operator= example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
std::mutex mtx; // mutex for critical section
void print_fifty () {
std::unique_lock<std::mutex> lck; // default-constructed
lck = std::unique_lock<std::mutex>(mtx); // move-assigned
for (int i=0; i<50; ++i)
{
if (lck.owns_lock())
std::cout << '*';
else
std::cout << '#';
}
std::cout << '\n';
}
int main ()
{
std::thread th1 (print_fifty);
th1.join();
return 0;
}
输出:
**************************************************
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。