在这篇文章中,我们要讨论的并不是QMutex的原理或者是应该如何使用,而是QMutex中一个很少被提到的优化细节。
我们知道在QT中,QMutex通常会和QMutexLocker一起使用,主要的用途是保护一个对象、数据结构或代码段,以便一次只让一个线程可以访问它们。 这一点对于多线程程序来说非常重要,而如今的程序已经离不开多线程,所以QMutex的使用场景也是越来越多,为了提高QMutex的使用效率,QT在QMutex的实现上加入了一个优化细节,这是std::mutex没有的,让我们来看看这个优化具体是什么。
QMutex的基类QBasicMutex有一个类型为QBasicAtomicPointer<QMutexData>成员,这里可以先忽略QBasicAtomicPointer,它只是保证对指针的原子操作,正在发挥作用的是QMutexData*。QMutexData类型也没有什么特殊之处,真正的优化是在它的派生类QMutexPrivate,来看一段QMutexPrivate的代码:
class QMutexPrivate : public QMutexData |
可以看到,当引用计数为0的时候调用的release函数并没有真正释放互斥体对象,而是调用了一个freelist的release函数。追踪freelist()会发现这样一段代码:
namespace { |
这下就豁然开朗了,QFreeList可以被认为是缓存池,用于维护QMutexPrivate的内存,当QMutexPrivate调用release函数的时候,QT并不会真的释放对象,而是将其加入到缓存池中,以便后续代码申请使用。这样不但可以减少内存反复分配带来的开销,也可以减少反复分配内核对象代码的开销,对于程序的性能是有所帮助的。
具体QFreeList的实现并不复杂,大家可以参考QT中的源代码qtbase\src\corelib\tools\qfreelist_p.h,另外除了QMutex以外,QRecursiveMutex和QReadWriteLock也用到了相同的技术。