整理mutex等互斥资源的常用用法
如果写多线程程序,那么需要通过加锁的方式来实现同步和互斥。c++标准库提供了mutex库。
参考链接:
Mutex基本语法
mutex提供了下面的几个类
- std::mutex:基本的互斥锁
- std::recursive_mutex:递归互斥锁,允许同一个线程多次锁定。
- std::timed_mutex:具有超时功能的互斥锁。
- std::recursive_timed_mutex:具有超时功能的递归互斥锁。
mutex的基本用法
使用mutex基本语法获取锁,常用lock(),try_lock(),unlock()等函数进行操作。
- lock()函数:当前线程获取互斥锁资源,如果互斥锁资源被其他线程占用,当前线程会被阻塞。
- try_lock()函数:当前线程尝试获取互斥锁资源,如果获取资源成功,该函数返回true。如果获取资源失败,该函数返回false。
- unlock()函数:释放当前互斥锁资源。
lock()
使用mutex的lock()函数去获取互斥锁。
通过执行结果时,能看到没有获取到锁资源的线程会阻塞等待前面的线程释放资源。
#include <iostream>
#include <thread>
#include <mutex>
int32_t gNumM = 0;
std::mutex mtx;
void incrementWithMutex(int32_t id)
{
std::cout << "function IN, id=" << id << std::endl;
mtx.lock();
std::cout << "lock get by" << id << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3)); //长时间占用锁
for(int32_t i=0; i<5000; i++)
{
gNumM++;
}
mtx.unlock();
std::cout << "unlock get by" << id << std::endl;
}
int main()
{
std::thread t1(incrementWithMutex, 1);
std::thread t2(incrementWithMutex, 2);
t1.join();
t2.join();
std::cout << gNumM << std::endl;
return 0;
}
运行结果:
function IN, id=1
lock get by1
function IN, id=2
unlock get by1
lock get by2
unlock get by2
10000
try_lock()
使用try_lock()尝试获取资源锁,没有获取到锁的情况下,会返回false。不会阻塞。
#include <iostream>
#include <thread>
#include <mutex>
int32_t gNumM = 0;
std::mutex mtx;
void incrementWithMutex(int32_t id)
{
std::cout << "function IN, id=" << id << std::endl;
if(mtx.try_lock())
{
std::cout << "lock get by" << id << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3)); //长时间占用锁
gNumM += 5000;
mtx.unlock();
std::cout << "unlock get by" << id << std::endl;
}
}
int main()
{
std::thread t1(incrementWithMutex, 1);
std::thread t2(incrementWithMutex, 2);
t1.join();
t2.join();
std::cout << gNumM << std::endl;
return 0;
}
t2没有获得锁,直接return,没有被阻塞,等到一直取得锁。
function IN, id=1
lock get by1
function IN, id=2
unlock get by1
5000
unlock()
在使用lock()或try_lock()后,必须使用unlock释放锁
不释放锁的情况:
#include <iostream>
#include <thread>
#include <mutex>
int32_t gNumM = 0;
std::mutex mtx;
void incrementWithMutex(int32_t id)
{
std::cout << "function IN, id=" << id << std::endl;
if(mtx.try_lock())
{
std::cout << "lock get by" << id << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3)); //长时间占用锁
gNumM += 5000;
//mtx.unlock();
//std::cout << "unlock get by" << id << std::endl;
}
std::cout << "function OUT, id=" << id << std::endl;
}
int main()
{
std::thread t1(incrementWithMutex, 1);
t1.join();
std::this_thread::sleep_for(std::chrono::seconds(5));
std::thread t2(incrementWithMutex, 2);
t2.join();
std::cout << gNumM << std::endl;
return 0;
}
t1已经执行完了,因为没有释放锁,t2无法获取到锁资源。
function IN, id=1
lock get by1
function OUT, id=1
function IN, id=2
function OUT, id=2
5000
同一线程对在没释放资源的情况下对同一个锁再加锁,会造成死锁。
#include <iostream>
#include <thread>
#include <mutex>
int32_t gNumM = 0;
std::mutex mtx;
void display()
{
std::cout << "display IN" << std::endl;
mtx.lock();
std::cout << "gNumM=" << gNumM << std::endl;
mtx.unlock();
}
void incrementWithMutex(int32_t id)
{
std::cout << "function IN, id=" << id << std::endl;
if(mtx.try_lock())
{
std::cout << "lock get by" << id << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3)); //长时间占用锁
gNumM += 5000;
display();
mtx.unlock();
std::cout << "unlock get by" << id << std::endl;
}
std::cout << "function OUT, id=" << id << std::endl;
}
int main()
{
std::thread t1(incrementWithMutex, 1);
t1.join();
std::cout << gNumM << std::endl;
return 0;
}
function IN, id=1
lock get by1
display IN
->程序会卡死在这里
recursive_mutex
递归互斥锁,同一个线程可以多次锁定同一个互斥锁。
#include <iostream>
#include <thread>
#include <mutex>
int32_t gNumM = 0;
std::mutex mtx;
std::recursive_mutex rMtx;
void display()
{
std::cout << "display IN" << std::endl;
rMtx.lock();
std::cout << "gNumM=" << gNumM << std::endl;
rMtx.unlock();
}
void incrementWithMutex(int32_t id)
{
std::cout << "function IN, id=" << id << std::endl;
if(rMtx.try_lock())
{
std::cout << "lock get by" << id << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3)); //长时间占用锁
gNumM += 5000;
display();
rMtx.unlock();
std::cout << "unlock get by" << id << std::endl;
}
std::cout << "function OUT, id=" << id << std::endl;
}
int main()
{
std::thread t1(incrementWithMutex, 1);
t1.join();
std::cout << gNumM << std::endl;
return 0;
}
使用recursive_mutex不会导致线程死锁
lock get by1
display IN
gNumM=5000
unlock get by1
function OUT, id=1
5000
timed_mutex和recursive_timed_mutex.
lock()和try_lock()用法和mutex以及recursive_mutex的用法一样。新增了try_lock_for()和try_lock_until()函数,如果在指定时间内无法获取互斥锁,则返回false。
#include <iostream>
#include <thread>
#include <mutex>
std::timed_mutex tMtx;
std::recursive_timed_mutex rtMtx;
int32_t gNum = 0;
void increase(int32_t id)
{
std::cout << id << "increase in\n";
if(tMtx.try_lock_for(std::chrono::seconds(3)))
{
std::cout << id << "locking\n";
std::this_thread::sleep_for(std::chrono::seconds(5));
gNum = 5000;
tMtx.unlock();
}
std::cout << id << "quit\n";
}
int main()
{
std::thread t1(increase, 1);
std::thread t2(increase, 2);
t1.join();
t2.join();
std::cout << gNum << std::endl;
return 0;
}
线程2等待了3s就退出了,没有一直阻塞等待。
1increase in
1locking
2increase in
2quit
1quit
5000

浙公网安备 33010602011771号