加锁的最基本目的

线程的面对问题,简单的讲,就是线程安全问题。
数据增删改查,如果几个线程同时进行,则可能出现多删或多加入的情况,为了保证线程的安全,数据准确性,这时候必须要进行加锁。
C++ 11提供了四种锁 C++ 14和17又分别引进了新的锁

APIC++标准释义
mutexC++11最基本的互斥锁
timed_mutexC++11具有超时功能的互斥锁
recursive_mutexC++11递归锁(同一线程可重复加的互斥锁)
recursive_timed_mutexC++11具有超时功能的递归锁
shared_mutexC++17读写锁(同一时间多个线程共享读的权限,只有一个线程有写的权限)
shared_timed_mutexC++14具有超时功能的读写锁(看起来有点魔幻)

最简单的锁入门

#include<iostream>
#include <thread>
#include <mutex>
using namespace std;
int  counter_ = 0;
std::mutex mutex_;
/*
std::timed_mutex timed_mutex_;
void TestFunc1(int input)
{
	if (timed_mutex_.try_lock_for(chrono::milliseconds(100))) {
		for (int i = 0; i < input; i++) {
			std::this_thread::sleep_for(chrono::milliseconds(10));
			counter_++;
			cout << "thread id=" << std::this_thread::get_id() << "counter_ =" << counter_ << endl;
		}
		timed_mutex_.unlock(); //释放锁
	} else {
		cout << "thread id=" << std::this_thread::get_id() << "counter_ =" << counter_ << endl;
	}
	
}
*/
/*
//非递归锁,重复加锁会crash
std::recursive_mutex recursive_mutex_;
void TestFunc1(int input)
{
	mutex_.lock();
	for (int i = 0; i < input; i++) {
		mutex_.lock();
		counter_++;
		std::this_thread::sleep_for(chrono::milliseconds(10));
		cout << "thread id=" << std::this_thread::get_id() << "counter_ =" << counter_ << endl;
		mutex_.unlock();
	}
	mutex_.unlock();
}
//递归锁,重复加锁
void TestFunc1(int input)
{
	recursive_mutex_.lock();
	for (int i = 0; i < input; i++) {
		recursive_mutex_.lock();
		counter_++;
		std::this_thread::sleep_for(chrono::milliseconds(10));
		cout << "thread id=" << std::this_thread::get_id() << "counter_ =" << counter_ << endl;
		recursive_mutex_.unlock();
	}
	recursive_mutex_.unlock();
}
*/
void TestFunc1(int input)
{
	mutex_.lock();
	for (int i=0; i < input; i++) {
		counter_++;
		std::this_thread::sleep_for(chrono::milliseconds(10));
		cout << "thread id=" << std::this_thread::get_id() << "counter_ =" << counter_ << endl;
	}
	mutex_.unlock();
}

int main()
{
	cout << "main thread id=" << std::this_thread::get_id() << endl;
	thread thread_1 = std::thread(TestFunc1,200);
	thread thread_2 = std::thread(TestFunc1, 200);
	thread_1.join();
	thread_2.join();
	cout << "thread id=" << std::this_thread::get_id() << "counter_ =" << counter_ << endl;
}

不加锁问题,等输出1的时候,1已经被第二个线程累加到2
在这里插入图片描述
互斥锁加锁后,保证了在当前id为8328线程执行完毕下一个线程才开始执行
在这里插入图片描述
超时互斥锁 由于9792线程一直占有所属权,1452线程超过等待时间直接输出
在这里插入图片描述
递归锁,在同一线程加锁/解锁,不对导致死锁
在这里插入图片描述
超时递归锁略

mutex锁的总结

C++ 几种锁的基础API

方法说明
lock锁定互斥体,如果不可用,则阻塞
try_lock尝试锁定互斥体,如果不可用,直接返回
unlock解锁互斥体

递归锁的特殊性
recursive_mutex和recursive_timed_mutex的名称都带有recursive。叫做可递归或者可重入锁,指在同一个线程中,同一把锁可以加锁多次。这就避免了一些不必要的死锁。
超时锁的特有API

方法说明
try_lock_for接受一个时间范围,在这一段时间范围之内线程如果没有获得锁则被阻塞住
try_lock_until接受一个时间点作为参数,在指定时间点未到来之前线程如果没有获得锁则被阻塞住,如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false

互斥锁和递归锁的特点示意

  • 互斥锁 :某一时刻,只有一个线程可以获取互斥锁,在该互斥锁释放之前其他线程都不能获取该互斥锁。如果其他线程想要获取这个互斥锁,那么这个线程必须阻塞方式进行等待;
  • 递归锁:线程有A、B、C方法。它们都会对同一个数据进行修改,那么必须加锁了,但某系功能需要,ABC可能会按特殊条件发生互相嵌套调用,如果你用互斥锁你就锁死了。但用递归锁允许同一个线程多次加锁,需要注意的是解锁的次数与加锁次数必须匹配;其他线程如果想访问数据也讲被阻塞,直至当前线程彻底释放递归锁后;
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐