<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
QLibraryPrivate 类
QLibraryPrivate 类的重要性
Qt中能加载库或插件的几个类:
QLibrary ,
QPluginLoader ,
QFactoryLoader ,
QStaticPlugin (暂时不研究这个)
QLibrary 和 QPluginLoader 依赖的'私有数据类'都是 QLibraryPrivate, 一个QLibrary或QPluginLoader的对象都有一个QLibraryPrivate对象,对应一个库或插件;
QFactoryLoader 依赖的'私有数据类'是 QFactoryLoaderPrivate , 但 QFactoryLoaderPrivate 类中又包含了一个QLibraryPrivate列表,这个列表中有多个
QLibraryPrivate类型的元素,对应一系列的库或插件;
所以可见,QLibraryPrivate是Qt中与库或插件相关的核心数据类,每个库都对应一个QLibraryPrivate对象。
QLibraryPrivate类的一些重要成员如下:
- class QLibraryPrivate
- {
- public:
- #ifdef Q_OS_WIN
- HINSTANCE
- #else
- void *
- #endif
- pHnd;
-
- QString fileName, qualifiedFileName;
- QString fullVersion;
-
- bool load();
- bool loadPlugin();
- bool unload(UnloadFlag flag = UnloadSys);
- void release();
- QFunctionPointer resolve(const char *);
-
- static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString(),
- QLibrary::LoadHints loadHints = 0);
- ...
- QtPluginInstanceFunction instance;
-
-
-
-
-
-
-
- QPointer<QObject> inst;
-
-
-
-
-
-
-
-
-
-
-
- QJsonObject metaData;
- ...
- QLibrary::LoadHints loadHints;
-
- void updatePluginState();
- bool isPlugin();
-
- static inline QJsonDocument fromRawMetaData(const char *raw) {
- raw += strlen("QTMETADATA ");
-
-
- QByteArray json(raw, qFromLittleEndian<uint>(*(uint *)(raw + 8)) + 8);
- return QJsonDocument::fromBinaryData(json);
- }
-
- private:
- explicit QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints);
- ~QLibraryPrivate();
- void mergeLoadHints(QLibrary::LoadHints loadHints);
-
- bool load_sys();
- bool unload_sys();
- QFunctionPointer resolve_sys(const char *);
-
-
-
- QAtomicInt libraryRefCount;
-
- QAtomicInt libraryUnloadCount;
-
- enum { IsAPlugin, IsNotAPlugin, MightBeAPlugin } pluginState;
- friend class QLibraryStore;
- };
构造/析构类函数定义如下。其中构造函数中的参数 canonicalFileName是库的标准文件名,version是版本号,loadHints用于控制库加载
时的动作,比如在加载该库时而不是等到调用resolve时,就将库中的所有符号实例化(ResolveAllSymbolsHint)等。
构造函数只检查库文件名是否有效,析构函数中则什么也不做。findOrCreate函数是个静态函数,它能返回一个QLibraryPrivate指针,其作用与
QLibraryStore类的findOrCreate函数一致(本文后面有对QLibraryStore类及其findOrCreate函数的介绍)
- QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints)
- : pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0),
- loadHints(loadHints),
- libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin)
- {
- if (canonicalFileName.isEmpty())
- errorString = QLibrary::tr("The shared library was not found.");
- }
-
- QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version,
- QLibrary::LoadHints loadHints)
- {
- return QLibraryStore::findOrCreate(fileName, version, loadHints);
- }
-
- QLibraryPrivate::~QLibraryPrivate()
- {
- }
QLibraryPrivate类中需要我们格外关心的一个成员变量是 metaData, 其类型为 QJsonObject , 它描述了一系列与某个
库相关的元信息 , 元信息中包含有库或Qt插件的IDD、关键字Keys等重要信息。与元信息有关的内容在另外一片文章中单独介绍。
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
QLibraryStore (库商店)类
先看QLibraryStore类的定义
- QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints)
- : pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0),
- loadHints(loadHints),
- libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin)
- {
- if (canonicalFileName.isEmpty())
- errorString = QLibrary::tr("The shared library was not found.");
- }
-
- QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version,
- QLibrary::LoadHints loadHints)
- {
- return QLibraryStore::findOrCreate(fileName, version, loadHints);
- }
-
- QLibraryPrivate::~QLibraryPrivate()
- {
- }
注意一点:这个类没有多少干货,它所有的方法都是静态的! 只有一个非静态的实体成员 libraryMap 。
libraryMap是个QMap类型的映射表,它保存了从一个QString列表到一个QLibraryPrivate*列表的映射。其中,QString列表中是所有的库对应的库文件名,而
QLibraryPrivate列表中则是所有的库对应的QLibraryPrivate对象。除了这个列表外,QLibraryStore这个类没有任何其他
实体成员。在一个Qt应用程序或进程中,一般只需要一个这样的映射表,所以也就只需要一个 QLibraryStore 的实例,Qt 内部也确实是这么做
的,这可以从QLibrary.cpp文件中看出来 (QLibraryStore这个类的方法的具体定义基本都在QLibrary.cpp文件中):
首先,该文件中有如下几个全局静态变量:
- static QLibraryStore *qt_library_data = 0;
- static bool qt_library_data_once;
其中qt_library_data就是指向QLibraryStore类的一个静态全局实例的指针,外部通过调用QLibraryStore类的静态
方法 instance() 来访问它。而变量qt_library_data_once则用来标记qt_library_data是否曾被创建过。
这个方法定义如下:
- QLibraryStore *QLibraryStore::instance()
- {
- if (Q_UNLIKELY(!qt_library_data_once && !qt_library_data)) {
-
- qt_library_data = new QLibraryStore;
- qt_library_data_once = true;
- }
- return qt_library_data;
- }
- QLibraryStore::~QLibraryStore()
- {
- qt_library_data = 0;
- }
注意,qt_library_data虽然被初始化为了NULL,但当外部第一次调用QLibraryStore类的instance方法时,qt_library_data就变成有效指针了。
findOrCreate 方法用于从 QLibraryStore 的映射表中查找是否存在库文件名是fileName的库,如果存在则直接返回该库对应的QLibraryPrivate对象,
如果映射表中不存在,则new一个QLibraryPrivate对象并将其添加到映射表中。使用这个函数来获取 QLibraryPrivate 对象可以保证不会出现多个
QLibraryPrivate 对象映射到同一个库文件上的现象。
- inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, const QString &version,
- QLibrary::LoadHints loadHints)
- {
- QMutexLocker locker(&qt_library_mutex);
- QLibraryStore *data = instance();
-
-
- QLibraryPrivate *lib = 0;
- if (Q_LIKELY(data)) {
- lib = data->libraryMap.value(fileName);
- if (lib)
- lib->mergeLoadHints(loadHints);
- }
- if (!lib)
- lib = new QLibraryPrivate(fileName, version, loadHints);
-
-
- if (Q_LIKELY(data))
- data->libraryMap.insert(fileName, lib);
-
- lib->libraryRefCount.ref();
- return lib;
- }
与findOrCreate相对的函数是releaseLibrary,他负责释放一个库。但这个函数不一定会释放指定的库,而是先将库的引用计数减 1 ,只有引用计数变为0时才释放。
- inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib)
- {
- QMutexLocker locker(&qt_library_mutex);
- QLibraryStore *data = instance();
-
- if (lib->libraryRefCount.deref()) {
-
- return;
- }
-
- Q_ASSERT(lib->libraryUnloadCount.load() == 0);
-
- if (Q_LIKELY(data)) {
- QLibraryPrivate *that = data->libraryMap.take(lib->fileName);
- Q_ASSERT(lib == that);
- Q_UNUSED(that);
- }
- delete lib;
- }
QLibraryStore类的cleanup函数负责卸载(unload)所有不再使用的库,并释放映射表中所有的 QLibraryPrivate 对象
- inline void QLibraryStore::cleanup()
- {
- QLibraryStore *data = qt_library_data;
- if (!data)
- return;
-
-
- LibraryMap::Iterator it = data->libraryMap.begin();
- for (; it != data->libraryMap.end(); ++it) {
- QLibraryPrivate *lib = it.value();
- if (lib->libraryRefCount.load() == 1) {
- if (lib->libraryUnloadCount.load() > 0) {
- Q_ASSERT(lib->pHnd);
- lib->libraryUnloadCount.store(1);
- #ifdef __GLIBC__
-
-
-
- lib->unload(QLibraryPrivate::NoUnloadSys);
- #else
- lib->unload();
- #endif
- }
- delete lib;
- it.value() = 0;
- }
- }
-
- if (qt_debug_component()) {
-
- foreach (QLibraryPrivate *lib, data->libraryMap) {
- if (lib)
- qDebug() << "On QtCore unload," << lib->fileName << "was leaked, with"
- << lib->libraryRefCount.load() << "users";
- }
- }
-
- delete data;
- }