一、问题描述
当插件名称一样时,new的不同QPluginLoader对象instance方法获取实例地址是一样的,这样的话就无法创建多个实例。
QPluginLoader *loader = new QPluginLoader("Yolo5Plugin.dll");
QPluginLoader *loader2 = new QPluginLoader("Yolo5Plugin.dll");
二、源码解析
为了研究QPluginLoader为何是个单例模式,下面将一层一层剖析QT源码
1、首先查看instance实现代码,这里还看不出单例模式,但返回值是从d指针获取的,说明d指针可能是单例,d指针对应类为QLibraryPrivate。
QObject *QPluginLoader::instance()
{
if (!isLoaded() && !load())
return 0;
if (!d->inst && d->instance)
d->inst = d->instance();
return d->inst.data();
}
QLibraryPrivate *d;
2、d指针是如何赋值的? 可以发现是在setFileName函数中赋值的,来源于QLibraryPrivate::findOrCreate
void QPluginLoader::setFileName(const QString &fileName)
{
#if defined(QT_SHARED)
QLibrary::LoadHints lh = QLibrary::PreventUnloadHint;
if (d) {
lh = d->loadHints();
d->release();
d = 0;
did_load = false;
}
const QString fn = locatePlugin(fileName);
d = QLibraryPrivate::findOrCreate(fn, QString(), lh);
if (!fn.isEmpty())
d->updatePluginState();
#else
if (qt_debug_component()) {
qWarning("Cannot load %s into a statically linked Qt library.",
(const char*)QFile::encodeName(fileName));
}
Q_UNUSED(fileName);
#endif
}
3、接下来进入QLibraryPrivate::findOrCreate源码,发现返回值来源与instance()函数
QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version,
QLibrary::LoadHints loadHints)
{
return QLibraryStore::findOrCreate(fileName, version, loadHints);
}
inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, const QString &version,
QLibrary::LoadHints loadHints)
{
QMutexLocker locker(&qt_library_mutex);
QLibraryStore *data = instance();
// check if this library is already loaded
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);
// track this library
if (Q_LIKELY(data) && !fileName.isEmpty())
data->libraryMap.insert(fileName, lib);
lib->libraryRefCount.ref();
return lib;
}
4、再进入instance()函数,返回值来源与变量qt_library_data,而qt_library_data定义为static,这里还使用了静态变量qt_library_data_once保证了单例特性。在上一步骤中使用了加锁机制,所以还是一个线程安全的单例模式。
// must be called with a locked mutex
QLibraryStore *QLibraryStore::instance()
{
if (Q_UNLIKELY(!qt_library_data_once && !qt_library_data)) {
// only create once per process lifetime
qt_library_data = new QLibraryStore;
qt_library_data_once = true;
}
return qt_library_data;
}
static QBasicMutex qt_library_mutex;
static QLibraryStore *qt_library_data = 0;
static bool qt_library_data_once;
三、如何才能创建多个实例?
获取 instance 的对象后,对象提供一个创建该对象的方法。
DefectInterface *Yolo5Plugin::newInstance()
{
return new Yolo5Plugin();
}
DefectInterface *base = qobject_cast<DefectInterface *>(loader->instance());
DefectInterface *defect1 = base->newInstance();
DefectInterface *defect2 = base->newInstance();