1. unique_lock 何时锁定资源。
unique_lock lock1 时候,还没有锁住资源。 实际是后面,显式的出发: 比如, lock.lock, 或 std::lock(lk1,lk2), 或者条件变量CV.wait(mtx, []{!re})。
#include <iostream>
#include <mutex>
#include <thread>
#include "my_utils.h"
struct Box
{
explicit Box(int num) : num_things{num} {}
int num_things;
std::mutex m;
};
void transfer(Box& from, Box& to, int num)
{
// don't actually take the locks yet, e.g. conditional variable imp.
// no locking
std::unique_lock lock1{from.m, std::defer_lock};
std::unique_lock lock2{to.m, std::defer_lock};
SLEEP_FOR_500_MS();
SLEEP_FOR_500_MS();
// lock both unique_locks without deadlock
std::lock(lock1, lock2);
from.num_things -= num;
to.num_things += num;
// “from.m” and “to.m” mutexes unlocked in unique_lock dtors
}
int main()
{
Box acc1{100};
Box acc2{50};
std::thread t1{transfer, std::ref(acc1), std::ref(acc2), 10};
std::thread t2{transfer, std::ref(acc2), std::ref(acc1), 5};
acc1.num_things=199;
std::cout<<"main thrd starts wait for notifier!"<<acc1.num_things<<" no locking yet\n";
t1.join();
t2.join();
std::cout << "acc1: " << acc1.num_things << "\n"
"acc2: " << acc2.num_things << '\n';
}
运行结果,如下: 可见资源在 unique_lock 声明时候,还没有被锁定独享。
2. unique_lock 使用,常常是配合,触发锁定条件的,可以是时间timelockable,也可以是条件 lockable。
以下,一condional ariable 结合 unique_lock,为例:
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include "my_utils.h"
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// wait until main() sends data
std::unique_lock lk(m);
cv.wait(lk, []{ return ready; });
// after the wait, we own the lock
std::cout << "Worker thread is processing data\n";
data += " after processing";
// send data back to main()
processed = true;
std::cout << "Worker thread signals data processing completed\n";
// manual unlocking is done before notifying, to avoid waking up
// the waiting thread only to block again (see notify_one for details)
//“惊群效应”(thundering herd problem),即多个线程被唤醒,但只有一个线程能够立即获取到锁,其他线程会再次进入等待状态
lk.unlock(); //手动解锁允许你更灵活地控制这些操作何时发生, first unlock manue, then notify.
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Example data";
// send data to the worker thread
{
std::lock_guard lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();
// wait for the worker
{
std::unique_lock lk(m);
cv.wait(lk, []{ return processed; });
}
std::cout << "Back in main(), data = " << data << '\n';
worker.join();
}