Statische Variablen
Speicherallokation zwischen Windows- und Echtzeitkontext im Zusammenhang mit statischen Variablen
Wenn globale Instanzen verwendet werden, ist auf folgendes zu achten:
- Es dürfen maximal 32 globale Instanzen insgesamt existieren.
Dabei ist zu beachten, dass auch durch TwinCAT-eigene Module globale Instanzen genutzt werden können. Bei Überschreitung der Anzahl werden die Destruktoren nicht mehr aufgerufen. - Speicher, der im Echtzeit-Kontext allokiert wird, muss beispielsweise in der OS-Transition freigegeben werden, sodass dies nicht durch den Destruktor passiert.
- Wenn der Konstruktor ausgeführt wird, kann noch nicht auf Ressourcen des TwinCAT Systems zugegriffen werden, weil die Verbindung über die Classfactory zum TcCOM Objektserver noch nicht hergestellt ist. Weiter unten sehen Sie, wie damit umzugehen ist.
In diesem Code sind 3 Beispiele für globale Instanzen:
class MyClassA
{
public:
MyClassA() {}
~MyClassA() {}
private:
int v;
}
MyClassA A;
class MyClassB
{
static MyClassA Value;
};
MyClassA& GetInstance()
{
static MyClassA a;
return a;
}
Singletons für die Initalisierung globaler Instanzen
Um den Zeitpunkt hinauszuzögern, können globale bzw. sog. Singleton Instanzen auch als lokale statische Objekte angelegt werden. Ganz wichtig bei der Verwendung von globalen Klasseninstanzen ist, dass die Destruktoren spät aufgerufen werden und zu diesem Zeitpunkt keine Verbindung mehr zum TwinCAT System besteht, sodass Ressourcen von TwinCAT vorher freigegeben werden müssen.
Hier ist ein Beispielcode, der ein Singleton in TwinCAT zeigt:
#include "TcInterfaces.h"
class VersionProvider : public ITcVersionProvider
{
public:
DECLARE_IUNKNOWN_NODELETE()
VersionProvider()
{
m_Version = { 1, 2, 3, 0};
}
virtual HRESULT TCOMAPI GetVersion(T_Version& version)
{
version = m_Version;
return S_OK;
};
private:
T_Version m_Version;
};
BEGIN_INTERFACE_MAP(VersionProvider)
INTERFACE_ENTRY(IID_ITcVersionProvider, ITcVersionProvider)
END_INTERFACE_MAP()
class MySingleton
{
public:
static MySingleton& Instance(ITcVersionProvider* ip = NULL, bool bRelease=false)
{
static MySingleton g_instance(ip);
if (bRelease) g_instance.Release();
return g_instance;
}
T_Version GetVersion()
{
T_Version v = {0, 0, 0, 0};
if (m_spTcInst != NULL)
{
m_spTcInst->GetVersion(v);
}
return v;
}
private:
MySingleton(ITcVersionProvider* ip = NULL)
: m_spTcInst(ip)
{
}
void Release()
{
m_spTcInst = NULL;
}
ITcVersionProviderPtr m_spTcInst;
};
Hier wird die Verwendung gezeigt:
// actual instance which is an example for a TwinCAT resource
VersionProvider vp;
// Initialize singleton
MySingleton::Instance(&vp);
// use singleton to access information provided by TwinCAT resource
T_Version v1 = MySingleton::Instance().GetVersion();
Assert::IsTrue( v1.major == 1 && v1.minor == 2 && v1.build == 3 && v1.revision == 0);
// Deinitialize singleton and release reference to TwinCAT resource
MySingleton::Instance(NULL, true);
// use singleton after deinitialization which has to implement some default behaviour for this case
T_Version v2 = MySingleton::Instance().GetVersion();
Assert::IsTrue( v2.major == 0 && v2.minor == 0 && v2.build == 0 && v2.revision == 0);