CriticalSections
Instances of CriticalSections are created through TwinCAT real-time. This instance can be initialized in the Windows context as well as in the RT context. The CriticalSection instance can only be used in the RT context.
TwinCAT real-time uses "priority inheritance" to prevent a task with lower priority from indirectly blocking a task with high priority.
CCriticalSectionInstance
The CCriticalSectionInstance class provides the interface to handle Critical Sections and has the required memory. To create a Critical Section the class requires the object ID of the TwinCAT real-time instance, which is available via OID_TCRTIME_CTRL, as well as a reference to the TwinCAT object server via a pointer to ITComObjectServer.
Methods:
- CCriticalSectionInstance(OTCID oid=0, ITComObjectServer* ipSrv=NULL);
The default constructor that initializes the object ID of the Critical Section Provider. If the pointer is given to the object server, the Critical Section is also initialized. - ~CCriticalSectionInstance();
The destructor deletes the Cricital Section instance. - void SetOidCriticalSection(OTCID oid);
Sets the Critical Section Provider, which is given by TwinCAT real-time and whose object ID is available via OID_TCRTIME_CTRL. - bool HasOidCriticalSection();
Returns TRUE if the object ID is set to a value other than 0, otherwise FALSE. The object ID is not checked to verify whether it belongs to a Critical Section Provider. - bool IsInitializedCriticalSection();
Returns TRUE if the Critical Section was successfully initialized. - HRESULT CreateCriticalSection(ITComObjectServer* ipSrv);
If the Critical Section is initialized, it is deleted and a new Critical Section is initialized. Returns S_OK if successful. Error cases are indicated by the return of error codes:
ADS_E_INVALIDPARM | Invalid Critical Section Provider |
ADS_E_NOINTERFACE | The object ID is set to a reference that is not a Critical Section Provider, i.e. ITcRTime is not implemented. |
E_FAIL | Internal error from the Critical Section Provider. |
- HRESULT CreateCriticalSection(OTCID oid, ITComObjectServer* ipSrv);
Initializes the Critical Section. DeleteCriticalSection() must be called if this method is used again. Return values as in CreateCriticalSection(ITComObjectServer* ipSrv); - HRESULT DeleteCriticalSection(); Critical Section is deleted. Always returns S_OK.
- HRESULT EnterCriticalSection(); blocked until the Critical Section is released.
- HRESULT LeaveCriticalSection();
Leaves the Critical Section and thus releases it again.
Returns MAKE_RTOS_HRESULT(OS_CS_ERR) if the caller is not the owner.
EnterCriticalSection() and LeaveCriticalSection() must be called in the RT context, otherwise the following return value is returned:
ADS_E_INVALIDCONTEXT | Return value if Critical Section is entered outside the RT context. The Critical Section is not entered. |
If these methods are used without initializing the Critical Section, S_OK is returned without further action. All other methods can be used in the RT context as well as in the Windows context.
In the CCriticalSectionInstance class, the EnterCriticalSection() can be called multiple times by the same task. Leave() must then be called just as often.
CriticalSections allow nested calls and require an associated LeaveCriticalSection() call for each EnterCriticalSection() call. The Critical Section is released when the last LeaveCritcalSection() is called.
Sample:
The sample shows how to use a CriticalSection to prevent concurrent access to a date via an interface method call.
Critical Section Concurrent
The CCriticalSectionInstanceConcurrent class allows concurrent access. This can be used if several tasks have read access to the data to be protected, but all other accesses must be prevented in the case of write access.
Methods:
- CCriticalSectionInstanceConcurrent(UINT concurrent, OTCID oid=0, ITComObjectServer* ipSrv=NULL); The parameter "concurrent" defines the number of tasks that can simultaneously enter the Critical Section via CsEnterCriticalSectionConcurrent(). If "concurrent" is 1, the Critical Section Concurrent variant works like a Critical Section.
The value 0 is not allowed. It would prevent the Critical Section from being initialized. - ~CCriticalSectionInstanceConcurrent(); The destructor implicitly deletes the Critical Section
- void SetOidCriticalSection(OTCID oid); Sets the Critical Section Provider, which is given by TwinCAT real-time and whose object ID is available via OID_TCRTIME_CTRL.
- bool HasOidCriticalSection(); Returns TRUE if the object ID is set to a value other than 0, otherwise FALSE. The object ID is not checked to verify whether it belongs to a Critical Section Provider.
- bool IsInitializedCriticalSection(); Returns TRUE if the Critical Section was successfully initialized.
- HRESULT CreateCriticalSection(ITComObjectServer* ipSrv); If the Critical Section is initialized, it is deleted and a new Critical Section is initialized. Returns S_OK if successful. Error cases are indicated by the return of error codes:
ADS_E_INVALIDPARM | Invalid Critical Section Provider |
ADS_E_NOINTERFACE | The object ID is set to a reference that is not a Critical Section Provider, i.e. ITcRTime is not implemented. |
E_FAIL | Internal error from the Critical Section Provider. |
- HRESULT CreateCriticalSection(OTCID oid, ITComObjectServer* ipSrv);
Initializes the Critical Section. DeleteCriticalSection() must be called if this method is used again. Return values as in CreateCriticalSection(ITComObjectServer* ipSrv); - HRESULT DeleteCriticalSection(); Critical Section is deleted. Always returns S_OK.
- HRESULT EnterCriticalSection(); Blocked until the Critical Section is released and can be accessed exclusively.
- HRESULT LeaveCriticalSection(); Leaves the Critical Section and thus releases it again. Returns MAKE_RTOS_HRESULT(OS_CS_ERR) if the caller is not the owner.
- HRESULT EnterCriticalSectionConcurrent(); Enters the Critical Section in parallel with other tasks. The number of parallel accesses is defined by the parameter "concurrent" in the constructor. When this maximum number is reached, the call is blocked until one of the parallel accesses has ended.
EnterCriticalSection(), EnterCriticalSectionConcurrent() and LeaveCriticalSection() must be called in the RT context, otherwise the following return value is returned:
ADS_E_INVALIDCONTEXT | Return value if Critical Section is entered outside the RT context. The Critical Section is not entered. |
If these methods are used without initializing the Critical Section, S_OK is returned without further action. All other methods can be used in the RT context as well as in the Windows context.
For the CCriticalSectionInstanceConcurrent class, it is not allowed for the EnterCriticalSection() method to be called multiple times by the same task if the concurrent parameter is greater than 1 during initialization.