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