我已经实现了标准的单例模式(非线程版本),如下所示:
hpp:
#ifndef SERVICEMANAGER_H
#define SERVICEMANAGER_H
#include <QObject>
#include <QVariant>
#include <QMap>
#include "IService.h"
#include "qhcore_global.h"
#include <QDebug>
class ServiceManager : public QObject
{
Q_OBJECT
public:
static ServiceManager* instance();
~ServiceManager(){qDebug()<<Q_FUNC_INFO;}
IService* service(QString name);
bool registerService(IService* service);
private:
explicit ServiceManager(QObject *parent = nullptr);
QMap<QString, IService*> _serviceMap;
static ServiceManager* __instance;
signals:
void serviceAdded(QString serviceName);
public slots:
};
#endif // SERVICEMANAGER_H
cpp:
ServiceManager* ServiceManager::__instance = nullptr;
ServiceManager::ServiceManager(QObject *parent) : QObject(parent)
{
qDebug()<<"CREATE::CTOR";
}
ServiceManager* ServiceManager::instance()
{
qDebug()<< __instance << "BEFORE";
if(__instance == nullptr)
{
qDebug()<<"CREATE";
__instance = new ServiceManager();
qDebug()<< __instance << "AFTER";
}
return __instance;
}
我的日志如下所示
[DEBUG 17.11. - 17:50:18:748] --
[DEBUG 17.11. - 17:50:18:748] -- QObject(0x0) BEFORE
[DEBUG 17.11. - 17:50:18:748] -- CREATE
[DEBUG 17.11. - 17:50:18:748] -- CREATE::CTOR
[DEBUG 17.11. - 17:50:18:748] -- ServiceManager(0x55e9fc6fb510) AFTER
[DEBUG 17.11. - 17:50:18:748] -- 0
[INFO 17.11. - 17:50:18:748] -- "Service registered: lab"
[DEBUG 17.11. - 17:50:18:748] -- 1
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/logs"
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/users"
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/permissions"
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/cards"
[INFO 17.11. - 17:50:43:973] -- "::ffff:192.168.1.32" has connected.
[INFO 17.11. - 17:50:43:985] -- "admin logged in. (" 1 sessions open)
[INFO 17.11. - 17:50:43:985] -- Device registered: "4f2o4o7b1a1r"
[INFO 17.11. - 17:50:44:003] -- Create ListResource with FS Resource Handler "logger/mappings_synclist"
[INFO 17.11. - 17:50:44:005] -- Create ListResource with FS Resource Handler "labcontrol/logs_synclist"
[INFO 17.11. - 17:50:44:007] -- Create ListResource with FS Resource Handler "labcontrol/users_synclist"
[INFO 17.11. - 17:50:44:009] -- Create ListResource with FS Resource Handler "labcontrol/permissions_synclist"
[INFO 17.11. - 17:50:44:011] -- Create ListResource with FS Resource Handler "labcontrol/cards_synclist"
[DEBUG 17.11. - 17:50:45:136] -- QObject(0x0) BEFORE
[DEBUG 17.11. - 17:50:45:136] -- CREATE
[DEBUG 17.11. - 17:50:45:136] -- CREATE::CTOR
[DEBUG 17.11. - 17:50:45:137] -- ServiceManager(0x55e9fc749340) AFTER
[DEBUG 17.11. - 17:50:45:137] -- COUNT: 0
[DEBUG 17.11. - 17:50:45:137] -- ()
[WARNING 17.11. - 17:50:45:138] -- "Unavailable servcie: lab"
在日志中,您可以看到单例将被实例化两次。第二次调用instance()函数时,私有静态成员__instance再次持有nullptr。这是完全奇怪的。相同的代码可以在具有不同平台(OSx,Raspbian等)的其他计算机上完美运行。
我的系统是运行Ubuntu Server 18.10 x64的beelink BT3 pro。代码本身是基于WebSocket的IoT Cloud,结合使用Qt5和插件。
我尝试过的事情:
使用不同的编译器,例如gcc-8,gcc-7和gcc-6。 我自己编译Qt,以确保所有二进制文件都使用相同的编译器构建。
再次:“我的应用”使用插件。可能与单例对象用于不同的插件中有关,该插件在运行时通过QPluginLoader从共享对象文件中加载。
edit:我不使用线程,也不使用其他名称空间。
欢迎任何提示!预先感谢!
EDIT2 (解决方案):
(移至下面的答案。)
答案 0 :(得分:2)
您应该使用宏Q_GLOBAL_STATIC()在插件之间共享实例。可以这样重写cpp文件:
const data = [
{"PermCode":"BOF","IsvalidPerm":true},
{"PermCode":"CM","IsvalidPerm":false},
{"PermCode":"CV","IsvalidPerm":true},
{"PermCode":"DAS","IsvalidPerm":true},
{"PermCode":"RPT","IsvalidPerm":true},
{"PermCode":"VM","IsvalidPerm":true}
];
const formatted = data.reduce((acc, curr) => ({ ...acc, [curr.PermCode]: curr.IsvalidPerm }), {});
console.log(formatted);
答案 1 :(得分:1)
如果您将ServiceManager.cpp
(或ServiceManager.o
)静态链接到多个动态库,则每个动态库最终都可能包含其自己的ServiceManager::__instance
实例。
解决方案是将ServiceManager.o
放入一个单独的动态库,该库可供您所有“插件”库使用。
答案 2 :(得分:0)
不幸的是,之前的答案没有奏效……仍然是同样的问题。 但..我发现了问题:
在我的应用程序中有几个独立的插件和核心插件。最后一个是两者:一个插件和所有其他插件的共享库。 我的应用程序有一个相对的搜索路径,用于查找要加载的插件。到目前为止,一切都很好。但是独立的扩展插件需要在运行时找到要链接的核心插件。因此,我将核心插件复制到了/ usr / lib。这就是问题所在。 libCorePlugin.so有两个副本-一个在plugin文件夹中,另一个在/ usr / lib中。我不知道为什么这在所有其他机器上都起作用...但是让LD_LIBRARY_PATH指向公共插件文件夹,而不是将文件复制到/ usr / lib即可解决此问题。
有人知道为什么以前在某些系统上可以使用吗?