C++11多线程——lock详解

本文详细介绍了C++11中用于多线程管理锁的两个类:lock_guard和unique_lock。lock_guard提供RAII特性,确保在对象生命周期内始终保持锁的状态,而unique_lock则更灵活,允许在需要时手动控制锁的获取和释放。文章通过构造函数和成员函数的讲解,展示了它们各自的特点和使用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++11提供了两种管理锁的类

  • std::lock_guard:与mutex RAII相关,方便线程对互斥量上锁
  • std::unique_lock:   与mutex RAII相关,方便线程对互斥量上锁,相比std::lock_guard提供了更好的上锁和解锁控制

一 lock_guard详解

  • lock_guard是一个模板类:template<classMutex>class lock_guard;
  • lock_guard对象通常用来管理某个锁(Lock)对象,与Mutex RALL相关,方便线程对互斥量上锁,在其声明周期内,它管理的锁一直保持上锁状态;在其声明周期结束之后,它锁管理的锁会被自动释放(即用构造函数对锁对象上锁,析构函数对锁对象解锁)

  • 模板参数Mutex代表几种基本的BasicLockable类型分别为:std::mutex, std::recursive_mutex, std::timed_mutex, std::recursive_timed_mutex以及 std::unique_lock, (BasicLockable类型只需满足两种操作,lock和unlock。Lockable类型在BasicLockable的基础上增加了try_lock操作。TimedLockable类型在Lockable的基础上又增加了try_lock_for和try_lock_until操作。)

  • 注意:lock_guard对象并不负责管理Mutex对象的生命周期,它只是简化了mutex的上锁和解锁操作,再其生命周期内,它锁管理的锁对象会一直保持上锁状态;声明周期结束之后,它锁管理的锁对象会被自动解锁。其最大的优点是安全易用(在出现异常时依旧可以正确解锁,一定程度上避免了死锁)

  •    lock_guard构造函数如下所示

  • locking-constructor (a)                   exlicit lock_guard(mutex_type& m);

    adopting-constructor (b)               lock_guard(mutex_type&m,adopt_lock_ttag);

    copy(deleted) -constructor (c)     lock_guard(const lock_guard&) = delete;

     

    a locking-constructor

             lock_guard对象管理Mutex对象m,并在构造时对m上锁

    b adopting-constructor初始化

             lock_guard对象管理Mutex对象m,与locking初始化不同的是,Mutex对象以被当前线程锁住。(mutex对象用adopting::lock_guard管理,最终在调用lock_guard析构函数时,m锁对象会被自动解锁)

    c copy-constructor

             lock_guard的拷贝构造与移动构造均被禁用

  • locking-constructor examples

#include <iostream>
#include <thread>
#include <mutex>
#include <stdexcept>

std::mutex mtx;

void printEven(int x)
{
	if (0 == x % 2)
	{
		std::cout << x << " is even\n";
	}
	else
	{
		throw (std::logic_error("not even\n"));
	}
}

void printThreadID(int id)
{
	try
	{
		std::lock_guard<std::mutex>lck(mtx);
		printEven(id);
	}
	catch (std::logic_error&e)
	{
		//std::cout << e.what() << std::endl;
		std::cout << "[exception caught]\n";
	}
}

int main(int argc, _TCHAR* argv[])
{
	std::thread threads[10];

	for (int i = 0; i < 10;++i)
	{
		threads[i] = std::thread(printThreadID, i + 1);
	}

	for (auto &th : threads)
	{
		th.join();
	}
	return 0;
}


     在voidprintThreadID(int id)中,首先捕捉voidprintEven(int x)中抛出的异常,在try块内,首先对mtx锁对象构造lock_guard对象lck(此语句之后,mtx锁对象由lck管理),即在try块作用域内(也就是lck对象生命周期内),mtx锁对象被上锁,在lck生命周期结束时mtx锁对象自动解锁(在抛出异常时,依旧可正确解锁)。
  • adopting-constructor example

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值