理解多线程(三)--互斥量

std::mutex

mutex就是互斥量的意思,在c++中使用互斥量需要包含#include

引入互斥量

之前了解了线程访问公有数据是不安全的,所以使用互斥量来防治线程不安全的操作。
互斥量就是一个变量,只有两种状态,加锁和解锁。每一个互斥量管理一个公有数据,一个线程访问公有数据后,互斥量加锁,其他线程就不能访问,等待之前的线程访问完成解锁后,才能访问。

mutex分类

Mutex 系列类(四种)
std::mutex,基本Mutex 类。
std::recursive_mutex,递归 Mutex 类。
std::time_mutex,定时基本Mutex 类。
std::recursive_timed_mutex,定时递归 Mutex 类。

std::mutex

构造:不允许拷贝构造和move构造,初始化为解锁状态。
成员函数:
lock():加锁,如果已经被其他线程加锁了,则会阻塞
unlock():解锁,在线程没有获得锁是不能进行解锁
try_lock():尝试加锁,如果已经被其他线程加锁了,则不会阻塞,返回false。

mutex  mu;
int x{ 0 }; 
mu.lock();
x++;
mu.unlock();

std::recursive_mutex

std::mutex只能进行一次上锁解锁操作,std::recursive_mutex允许一个线程对一个互斥量多次上锁,但解锁次数也必须相同。

recursive_mutex  mu;
int x{ 0 }; 
mu.lock();mu.lock();
x++;
mu.unlock();mu.unlock();

std::timed_mutex

try_lock_for():
新增的成员函数,尝试一直阻塞一个时间段加锁,如果超过这个时间段没有获得锁则返回false
try_lock_until():
新增的成员函数,尝试在一个时间点前加锁,如果这个时间段没有获得锁则会返回false

  recursive_mutex  mu;
int x{ 0 }; 
		if (mu.try_lock_for(std::chrono::microseconds(10))) //尝试阻塞10秒加锁
		{
			++counter;
			mu.unlock(); //解锁
		}

自动加锁

上面的都是手动进行加锁和解锁,但有时如果人们加锁后忘记了了解锁,就会造成死锁,所以c++11封装了上面的加锁解锁操作,制作了std::lock_guard 与 std::unique_lock来进行自动的加锁和解锁操作。

std::lock_guard

std::lock_guard 在构造函数中进行加锁,析构函数中进行解锁。所以我们可以在栈上创建std::lock_guard,在生命周期结束后,自动解锁。

int x {0 }; //原子变量
mutex mu; //互斥量
void fun()
{
	std::lock_guard<std::mutex> lock(mu);
	this_thread::sleep_for(std::chrono::microseconds(100));
	x++;
}
int main()
{
	for (size_t i = 0; i < 100; i++)
	{
		std::thread(fun).detach();
	}
	this_thread::sleep_for(std::chrono::microseconds(5000));
	cout << x << endl;
	system("pause");
	return 0;
}

std::unique_lock

std::unique_lock比std::lock_guard功能更加强大,但是会耗费更多的时间和空间。

猜你喜欢

转载自blog.csdn.net/qq_35651984/article/details/84930050