CriticalSections
Instanzen von Critical Sections werden durch die TwinCAT Realtime angelegt. Diese Instanz kann sowohl im Windows-Kontext wie auch im RT-Kontext initialisiert werden. Genutzt werden kann die Critical Section Instanz nur im RT-Kontext.
Die TwinCAT Realtime nutzt dabei “priority inheritance” um zu verhindern, dass eine Task mit geringerer Priorität indirekt einen Task mit hoher Priorität blockiert.
CCriticalSectionInstance
Die Klasse CCriticalSectionInstance bietet die Schnittstelle an, um Critical Sections zu handhaben und besitzt den nötigen Speicher. Um eine Critical Section anzulegen, benötigt die Klasse die Objekt-ID der TwinCAT Realtime Instanz, welche über OID_TCRTIME_CTRL bereitsteht, sowie eine Referenz zu dem TwinCAT Objekt-Server über einen Pointer auf ITComObjectServer.
Methoden:
- CCriticalSectionInstance(OTCID oid=0, ITComObjectServer* ipSrv=NULL);
Der Default Konstruktor, der die Objekt ID des Critical Section Providers initialisiert. Wenn der Pointer zu dem Objekt-Server gegeben wird, wird die Critical Section auch initialisiert. - ~CCriticalSectionInstance();
Der Destruktor löscht die Cricital Section Instanz. - void SetOidCriticalSection(OTCID oid);
Setzt den CriticalSection Provider, welcher durch die TwinCAT Realtime gegeben ist und dessen Objekt ID über OID_TCRTIME_CTRL verfügbar ist. - bool HasOidCriticalSection();
Gibt TRUE zurück, wenn die Obekt-ID zu einem Wert ungleich 0 gesetzt ist – sonst FALSE. Die Objekt-ID wird dabei nicht überprüft, ob sie zu einem Critical Section Provider gehört. - bool IsInitializedCriticalSection();
Gibt TRUE zurück, wenn die Criticals Section erfolgreich initialisiert wurde. - HRESULT CreateCriticalSection(ITComObjectServer* ipSrv);
Wenn die Critical Section initialisiert ist, wird diese gelöscht und eine neue Critical Section initialisiert. Gibt im Erfolgsfall S_OK zurück. Fehlerfälle werden durch die Rückgabe der Fehlercodes angezeigt:
ADS_E_INVALIDPARM | Ungültiger Critical Section Provider |
ADS_E_NOINTERFACE | Die Objekt ID ist auf eine Referenz gesetzt, die kein Critical Section Provider darstellt, also ITcRTime nicht implementiert. |
E_FAIL | Interner Fehler von dem Ciritical Section Provider. |
- HRESULT CreateCriticalSection(OTCID oid, ITComObjectServer* ipSrv);
Initalisiert die Cristical Section. DeleteCriticalSection() muss aufgerufen werden, wenn diese Methode erneut verwendet wird. Rückgabewerte wie in CreateCriticalSection(ITComObjectServer* ipSrv); - HRESULT DeleteCriticalSection(); Critical Section wird gelöscht. Gibt immer S_OK zurück.
- HRESULT EnterCriticalSection(); Blockiert, bis die Critical Section freigegeben wurde.
- HRESULT LeaveCriticalSection();
Verlässt die Critical Section und gibt diese damit wieder frei.
Es wird MAKE_RTOS_HRESULT(OS_CS_ERR) zurückgegeben, wenn der Aufrufende nicht der Besitzer ist.
EnterCriticalSection() und LeaveCriticalSection() müssen im RT-Kontext aufgerufen werden, ansonsten wird folgender Rückgabewert zurückgegeben:
ADS_E_INVALIDCONTEXT | Rückgabewert, wenn Critical Section außerhalb der RT Kontext betreten wird. Die Critical Section wird nicht betreten. |
Wenn diese Methoden genutzt werden, ohne dass die Critical Section initialisiert wurde, wird S_OK zurückgegeben, ohne dass etwas gemacht wird. Alle anderen Methoden können sowohl im RT-Kontext wie auch im Windows-Kontext benutzt werden.
Bei der Klasse CCriticalSectionInstance kann das EnterCriticalSection()mehrfach von derselben Task aufgerufen werden. Es muss dann Leave() genauso oft aufgerufen werden.
CriticalSections erlauben verschachtelte („nested“) Aufrufe und verlangen für jeden EnterCriticalSection()-Aufruf einen zugehörigen LeaveCriticalSection()-Aufruf. Die Freigabe der Critical Section ergibt sich dann beim Aufruf des letzten LeaveCritcalSection().
Beispiel:
Das Beispiel zeigt eine Nutzung einer CriticalSection um über einen Interface-Methodenaufruf eine gleichzeitigen Zugriff auf ein Datum zu verhindern.
Critical Section Concurrent
Die Klasse CCriticalSectionInstanceConcurrent erlaubt einen konkurrierenden Zugriff (Concurrent access). Dieser kann genutzt werden, wenn mehrere Tasks lesend auf die zu schützenden Daten zugreifen, aber bei einem schreibenden Zugriff alle anderen Zugriffe unterbunden werden müssen.
Methoden:
- CCriticalSectionInstanceConcurrent(UINT concurrent, OTCID oid=0, ITComObjectServer* ipSrv=NULL); Der Parameter “concurrent” definiert die Anzahl der Tasks, die gleichzeitig die Critical Section via CsEnterCriticalSectionConcurrent() betreten können. Wenn “concurrent” 1 ist, arbeitet die Critical Section Concurrent wie eine Critical Section.
Der Wert 0 ist nicht erlaubt und die Critical Section kann dann nicht initialisiert werden. - ~CCriticalSectionInstanceConcurrent(); Der Destruktor löscht implizit die Critical Section
- void SetOidCriticalSection(OTCID oid); Setzt den CriticalSection Provider, welcher durch die TwinCAT Realtime gegeben ist und dessen Objekt ID über OID_TCRTIME_CTRL verfügbar ist.
- bool HasOidCriticalSection(); Gibt TRUE zurück, wenn die Obect-ID zu einem Wert ungleich 0 gesetzt ist – sonst FALSE. Die Objekt-ID wird dabei nicht überprüft, ob sie zu einem Critical Section Provider gehört.
- bool IsInitializedCriticalSection(); Gibt TRUE zurück, wenn die Criticals Section erfolgreich initialisiert wurde.
- HRESULT CreateCriticalSection(ITComObjectServer* ipSrv); Wenn die Critical Section initialisiert ist, wird diese gelöscht und eine neue Critical Section initialisiert. Gibt im Erfolgsfall S_OK zurück. Fehlerfälle werden durch die Rückgabe der Fehlercodes angezeigt:
ADS_E_INVALIDPARM | Ungültiger Critical Section Provider |
ADS_E_NOINTERFACE | Die Objekt ID ist auf eine Referenz gesetzt, die kein Critical Section Provider darstellt, also ITcRTime nicht implementiert. |
E_FAIL | Interner Fehler von dem Critical Section Provider. |
- HRESULT CreateCriticalSection(OTCID oid, ITComObjectServer* ipSrv);
Initialisiert die Cristical Section. DeleteCriticalSection() muss aufgerufen werden, wenn diese Methode erneut verwendet wird. Rückgabewerte wie in CreateCriticalSection(ITComObjectServer* ipSrv); - HRESULT DeleteCriticalSection(); Critical Section wird gelöscht. Gibt immer S_OK zurück.
- HRESULT EnterCriticalSection(); Blockiert, bis die Critical Section freigegeben wurde und exklusiv betreten werden kann.
- HRESULT LeaveCriticalSection(); Verlässt die Critical Section und gibt diese damit wieder frei. Es wird MAKE_RTOS_HRESULT(OS_CS_ERR) zurückgegeben, wenn der Aufrufende nicht der Besitzer ist.
- HRESULT EnterCriticalSectionConcurrent(); Betritt die Critical Section parallel mit anderen Tasks. Die Anzahl der parallelen Zugriffe ist durch den Parameter “concurrent” im Konstruktor definiert. Wenn diese maximale Anzahl erreicht ist, blockiert der Aufruf, bis einer der parallelen Zugriffe beendet wurde.
EnterCriticalSection(), EnterCriticalSectionConcurrent() und LeaveCriticalSection() müssen im RT-Kontext aufgerufen werden, ansonsten wird folgender Rückgabewert zurückgegeben:
ADS_E_INVALIDCONTEXT | Rückgabewert, wenn Critical Section außerhalb der RT Kontext betreten wird. Die Critical Section wird nicht betreten. |
Wenn diese Methoden genutzt werden, ohne dass die Critical Section initialisiert wurde, wird S_OK zurückgegeben, ohne dass etwas gemacht wird. Alle anderen Methoden können sowohl im RT-Kontext wie auch im Windows-Kontext benutzt werden.
Bei der Klasse CCriticalSectionInstanceConcurrent, ist es nicht erlaubt, dass die Methode EnterCriticalSection() mehrfach von derselben Task aufgerufen wird, wenn der Parameter concurrent beim Initialisieren größer als 1 ist.