Reputation: 21
I have implemented the standard singleton pattern (the non threaded version) like this:
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;
}
and my log looks like this
[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"
In the log you can see that the singleton will be instantiated twice. The second time I call the instance() function, the private static member __instance holds a nullptr again. This is totally strange. The same code runs perfectly on other machines with different platforms (OSx, Raspbian, ...).
My system is a beelink BT3 pro running Ubuntu Server 18.10, x64. The code itself is a WebSocket based IoT Cloud which uses Qt5 in combination with plugins.
What I tried:
using different compilers such as gcc-8, gcc-7 and gcc-6. Compiling Qt by my own to ensure that all binaries are built with the same compiler.
Again: My App uses plugins. It probably has something to do with the fact that the singleton object is used within different plugins, loaded at runtime from shared object files via QPluginLoader.
edit: I don't use threads and I don't use different namespaces.
Any hint is welcome! Thanks in advance!
EDIT2 (SOLUTION):
(moved to my answer below.)
Upvotes: 0
Views: 872
Reputation: 21
Unfortunately the answers before didn't worked ... Still the same problem. BUT.. I found the problem:
In my application are a couple of independent plugins and the core plugin. The last one is both: A plugin and a shared library for all the other plugins. My application has a relative search path where it looks for plugins to load. So far so good. But the independent extension plugins need to find the core plugin to link against at runtime. So I copied the core plugin to /usr/lib. This was the issue. There were two copies of the libCorePlugin.so - one in the plugin folder and the other one in /usr/lib. I don't know why this has worked on all the other machines... But let LD_LIBRARY_PATH point to the common plugin folder instead of copying the file to /usr/lib solved the problem.
Does anyone has an idea why this has worked on some systems before?
Upvotes: 0
Reputation: 1072
You should use the macro Q_GLOBAL_STATIC() to share the instance between plugins. The cpp file can be rewritten like this :
Q_GLOBAL_STATIC(ServiceManager, myServiceManagerInstance)
ServiceManager *ServiceManager::instance()
{
return myServiceManagerInstance();
}
Upvotes: 2
Reputation: 2406
If you statically link your ServiceManager.cpp
(or ServiceManager.o
) to multiple dynamic libraries, each of them may end up containing its own instance of ServiceManager::__instance
.
The solution for that would be to put ServiceManager.o
into a separate dynamic library available to all your "plugin" libraries.
Upvotes: 1