1. 头文件
#include <mutex>
2. 分类
- std::mutex——最基本的mutex类
- std::recursive_mutex——递归mutex类
- std::time_mutex——定时mutex类
- std::recursive_timed_mutex——定时递归mutex类
3. std::mutex
3.1 概念
std::mutex 是C++11 中最基本的互斥量,std::mutex 对象提供了独占所有权的特性——即非递归锁,而 std::recursive_lock 则可以递归地对互斥量对象上锁。
3.2 成员函数
1)构造函数:不允许拷贝构造,也不允许 move 拷贝,最初产生的 mutex 对象是处于 unlocked 状态的;
2)lock():调用线程将锁住该互斥量;
线程调用该函数会发生下面 3 种情况:
- 如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁;
- 如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住;
- 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock);
3)unlock():解锁,释放对互斥量的所有权;
4)try_lock():尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞;
线程调用该函数会出现下面 3 种情况:
- 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用 unlock 释放互斥量;
- 如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉;
- 如果当前互斥量被当前调用线程锁住,则会产生死锁;
3.3 示例
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
std::mutex mtx;
void PrintLock(int n, char c)
{
mtx.lock();
for(int i = 0; i < n; i++) {
cout << c;
}
cout<<'\n';
mtx.unlock();
}
int main()
{
std::thread t1(PrintLock, 50, '*');
std::thread t2(PrintLock, 50, '$');
t1.join();
t2.join();
return 0;
}
编译运行:
[root@192 mutex]# g++ -lpthread -o mutex mutex.cpp
[root@192 mutex]# ./mutex
**************************************************
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
[root@192 mutex]#
4. std::recursive_mutex
std::recursive_mutex 允许同一个线程对互斥量多次上锁(即递归上锁)来获得对互斥量对象的多层所有权,std::recursive_mutex 释放互斥量时需要调用与该锁层次深度相同次数的 unlock()。
注意:
lock()和unlock()的调用次数应该相同。
5. std::time_mutex
5.1 成员函数
1)try_lock_for():接受一个时间范围,表示在这一段时间范围之内线程如果没有获得锁则被阻塞住(与 std::mutex 的 try_lock() 不同,try_lock 如果被调用时没有获得锁则直接返回 false),如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。
2)try_lock_until():接受一个时间点作为参数,在指定时间点未到来之前线程如果没有获得锁则被阻塞住,如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。
5.2 示例
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
using namespace std;
std::timed_mutex mtx;
void fireworks () {
// waiting to get a lock: each thread prints "-" every 200ms:
while (!mtx.try_lock_for(std::chrono::milliseconds(200))) {
cout << "-";
}
// got a lock! - wait for 1s, then this thread prints "*"
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
cout << "*\n";
mtx.unlock();
}
int main ()
{
std::thread threads[10];
for (int i=0; i<10; ++i)
threads[i] = std::thread(fireworks);
for (auto& th : threads) th.join();
return 0;
}
编译运行:
[root@192 mutex]# g++ -lpthread -o try_lock_for try_lock_for.cpp
[root@192 mutex]# ./try_lock_for
------------------------------------*
----------------------------------------*
-----------------------------------*
------------------------------*
-------------------------*
--------------------*
---------------*
----------*
-----*
*
[root@192 mutex]#
6. std::lock_guard
#include <iostream>
#include <thread>
#include <mutex>
#include <stdexcept>
using namespace std;
std::mutex mtx;
void print_even (int x) {
if (x%2==0) std::cout << x << " is even\n";
else throw (std::logic_error("not even"));
}
void print_thread_id (int id) {
try {
std::lock_guard<std::mutex> lck (mtx);
print_even(id);
}
catch (std::logic_error&) {
std::cout << "[exception caught]\n";
}
}
int main ()
{
std::thread threads[10];
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_thread_id,i+1);
for (auto& th : threads) th.join();
return 0;
}
编译运行:
[root@192 mutex]# g++ -lpthread -o lock_guard lock_guard.cpp
[root@192 mutex]# ./lock_guard
2 is even
[exception caught]
[exception caught]
4 is even
[exception caught]
6 is even
[exception caught]
8 is even
[exception caught]
10 is even
[root@192 mutex]#
7. std::unique_lock
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void print_block (int n, char c) {
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;
}
编译运行:
[root@192 mutex]# g++ -lpthread -o unique_lock unique_lock.cpp
[root@192 mutex]# ./unique_lock
**************************************************
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$