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 lockingstd::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 deadlockstd::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 datastd::unique_lock lk(m);cv.wait(lk, []{ return ready; });// after the wait, we own the lockstd::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();
}