C++11 同步与互斥
C++11 同步与互斥
1. std中的锁
1.1 锁是实现互斥的方法,在std中实现了多种基本锁如下:
-
std::mutex:最基本的互斥锁,只能在同一线程中进行加锁和解锁操作。
-
std::recursive_mutex:递归互斥锁,允许同一线程多次加锁,但必须在同一线程中解锁相同次数。
-
std::timed_mutex:定时互斥锁,允许线程尝试加锁一段时间,如果超时则放弃锁。
-
std::recursive_timed_mutex:递归定时互斥锁,结合了递归和定时互斥锁的特性。
-
std::shared_mutex:共享互斥锁,允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。当一个线程持有写入权限时,其他所有线程都无法获取读取或写入权限,直到该线程释放写入权限。注意这是一个读写分离锁,即多个线程可以同时读取共享数据,但只有一个线程可以写入共享数据。当一个线程正在写入共享数据时,其他线程必须等待该线程完成写入操作后才能进行读取或写入操作。
-
std::shared_timed_mutex:定时共享互斥锁,结合了共享和定时互斥锁的特性。
这些锁类型都是线程安全的,可以在多线程环境下使用。选择哪种锁类型取决于具体的应用场景和需求。
1.2 锁的封装
为了更方便的管理互斥锁的生命周期,具有RAII特性,即在对象构造时获取资源,在对象析构时释放资源,从而保证资源的正确获取和释放。他利用此原理在析构函数中释放了锁,即可以达到自动释放锁的效果。
-
std::unique_lock<std::mutex> lock(mutex_)
可以在构造函数中传入一个互斥锁对象,当
std::unique_lock
对象被销毁时(出了作用域会自动销毁),它会自动释放互斥锁。同时,std::unique_lock
还提供了lock()
和unlock()
方法,可以手动控制互斥锁的加锁和解锁。/*unique_lock简单实现*/ template<class Mutex> class unique_lock { public: explicit unique_lock(Mutex& m) : mutex_(m) { mutex_.lock(); } ~unique_lock() { mutex_.unlock(); } private: Mutex& mutex_; };
-
std::lock_guard<std::mutex> lock(mutex_)
.当std::lock_guard
对象被销毁时,互斥锁会自动解锁。这样可以确保在std::lock_guard
对象的生命周期内,互斥锁一直处于锁定状态,从而避免了忘记解锁的问题。 -
std::scoped_lock
也是一个模板类,用于管理多个互斥锁。在创建std::scoped_lock
对象时,需要传入多个互斥锁对象,该对象会在std::scoped_lock
的构造函数中被锁定,当std::scoped_lock
对象被销毁时,所有互斥锁会自动解锁。这样可以确保在std::scoped_lock
对象的生命周期内,所有互斥锁都处于锁定状态,从而避免了死锁的问题。需要注意的是,std::scoped_lock
可以同时锁定多个互斥锁,但是不能锁定同一个互斥锁多次,否则会导致死锁。