C++11的标准库中有lock这个概念,其中主要用到std::lock_guard和std::unique_lock这两把锁,unique_lock 与lock_guard都能实现自动加锁与解锁功能,但是unique_lock要比lock_guard更灵活,但是更灵活的代价是占用空间相对更大一点且相对更慢一点。unique_lock相对lock_guard更灵活的地方在于:在等待中的线程,在等待期间可以解锁mutex,并在之后可以重新将其锁定,而lock_guard却不具备这样的功能。如果有异常被抛出,unique_lock 也能被构造,以致于mutex被解锁。
所以在一个作用域中只有一次加锁解锁操作则采用std::lock_guard,而在一个作用域中需要多次操作采用std::unique_lock。
lock:只有在没有被上锁时,lock才能被构造;已上锁就不能被构造,一直处于等待状态,等待锁被释放。构造时上锁,析构时解锁。
<condition_variable>下wait()进入函数时lock被解锁,当条件为false,则一直阻塞线程;当条件为true,且被触发或被执行,则退出函数,退出函数前lock被上锁。
#include <iostream> #include <thread> #include <mutex> #include <condition_variable> #if 1 std::mutex m; std::condition_variable cv; bool ready = false; bool processed = false; void worker_thread() { std::cout << "1\n"; std::unique_lock<std::mutex> lk(m); std::cout << "2\n"; cv.wait(lk, [] {return ready; }); //进入函数时lock被解锁,当条件为false,则一直阻塞线程;当条件为true,且被触发或被执行,则退出函数,退出函数前lock被上锁 std::cout << "7\n"; processed = true; lk.unlock(); //lock解锁后,上锁优先级大于构造优先级 or wait函数先入列,所以先被调用 std::cout << "8\n"; getchar(); processed = true; cv.notify_one(); std::cout << "12\n"; } int main() { std::thread worker1(worker_thread); std::thread worker2(worker_thread); getchar(); std::cout << "3\n"; { std::lock_guard<std::mutex> lk(m); //只有在没有被上锁时,lock才能被构造;已上锁就不能被构造,一直处于等待状态,等待锁被释放。构造时上锁,析构时解锁; std::cout << "4\n"; ready = true; } std::cout << "5\n"; getchar(); cv.notify_all(); std::cout << "6\n"; { std::unique_lock<std::mutex> lk(m); //只有在没有被上锁时,lock才能被构造,构造时上锁,析构时解锁 std::cout << "9\n"; cv.wait(lk, [] {return processed; }); std::cout << "10\n"; processed = false; } { std::unique_lock<std::mutex> lk(m); std::cout << "11\n"; cv.wait(lk, [] {return processed; }); std::cout << "13\n"; } worker1.join(); worker2.join(); getchar(); return 0; } #else std::mutex m; void worker_thread() { std::unique_lock<std::mutex> lk(m); std::cout << "thread1" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::cout << "thread2" << std::endl; std::cout << "thread3" << std::endl; } int main(void) { std::thread worker1(worker_thread); std::thread worker2(worker_thread); std::thread worker3(worker_thread); { std::unique_lock<std::mutex> lk(m); std::cout << "main" << std::endl; std::cout << "main" << std::endl; std::cout << "main" << std::endl; } getchar(); //worker.join(); return 0; } #endif
1 2 1 2 3 4 5 6 7 8 7 8 9 10 11 12 13 12
thread1 thread2 thread3 thread1 thread2 thread3 thread1 thread2 thread3 main main main