在C++11中,引入了thread线程库,而为了应对线程的同步,又引入了互斥量mutex,而又因为mutex的各种问题,后续又引申出了使得mutex更安全的机制。
下面就以我的个人理解,介绍一下。
值得注意的是,下面的内容不涉及到详细的类的使用,而是仅仅对于他们之间的关系做一个梳理。
thread库是为了提高应用程序的效率而产生的,但是在thread中,同步却成了一个问题,为了解决这个问题,就引入了一个共享的互斥量mutex。多个线程如果使用的是同一个mutex。mutex有两种状态:lock和unlock,线程可以通过mutex的锁定与否来判断自己是否可以执行下面的操作。
mutex确实好用,但是mutex本身并不安全,譬如说mutex在执行lock操作之后、unlock操作之前的这段时间,代码出现了异常,导致解锁的代码没有执行,那么就导致mutex一直处于锁定状态,会造成程序的死锁deadlock。
为了解决这个问题,引入了两个局部变量:lock_guard和unique_lock,通过这两个局部变量的构造函数和析构函数,就可以实现对于mutex的上锁和解锁。前提,注意是这两个东西必须是局部变量,因为局部变量本身是有一个比较合理的生命周期的。
上述方法对于mutex的安全性能有了较大的提升。
但是,也是有这局限性,因为有时候我只想让某个线程在只有满足某一个条件的情况下才执行,这个时候如果仅仅采用mutex就不行了,因而引入了另一个东西:condition_variable条件变量。
condition_variable这个东西,有两个主要的函数,一个等待wait,一个通知唤醒notify。
不过condition_variable本身是不直接对于mutex进行操作的,它是通过unique_lock来间接操作mutex(不过本质上还是在操作mutex,只不过多出了一些条件)。结合notify函数和wait函数的第二个参数(谓语参数,也是条件参数),就可以实现对于某个条件下唤醒线程的功能。
如果想要扩大范围,不仅仅局限于unique_lock,可以使用condition_variable_any,这个也可以将lock_guard作为其参数。
另外,mutex本身就是一个资源,如果涉及到安全而使用了lock_guard或者是unique_lock之后,系统的资源占用会更加厉害。在我仅仅想要共享一个或者是少量的数据的时候,这种开销着实不小。
鉴于此,为了在某些情况下的性能开销,引入了一个被称之为原子量atomic的东西,这玩意在创造出来的时候,本身就具有线程同步的特性。
可以使用模板的方式,也可以使用特化版本诸如atomic_flag等的方法来执行操作。
以上就是大体的关系。根本上还是mutex,其他的东西基本上都是为了mutex进行服务的,使得代码更安全,更方便便捷。