Static variables
Memory allocation between Windows and real-time context in conjunction with static variables
If global instances are used, be aware of the following:
- A maximum of 32 global instances may exist in total.
It should be noted that global instances can also be used by TwinCAT's own modules. If the number is exceeded, the destructors are no longer called. - Memory allocated in the real-time context must be released in the OS transition, for example, so that this does not happen via the destructor.
- When the constructor is executed, TwinCAT system resources cannot yet be accessed, because the connection via the Classfactory to the TcCOM object server has not yet been established. Below you will see how to deal with this.
This code includes three examples of global instances:
class MyClassA
{
public:
MyClassA() {}
~MyClassA() {}
private:
int v;
}
MyClassA A;
class MyClassB
{
static MyClassA Value;
};
MyClassA& GetInstance()
{
static MyClassA a;
return a;
}
Singletons for the initialization of global instances
In order to delay the time, global or so-called singleton instances can also be created as local static objects. It is very important when using global class instances that the destructors are called late and at this point there is no longer a connection to the TwinCAT system, so that TwinCAT resources must be released beforehand.
Here is a sample code showing a singleton in TwinCAT:
#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;
};
Here the usage is shown:
// 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);