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;
}
输入:
**************************************************