Hilfe bei Guardklasse
-
Nur statische Objekte sind aber nicht gerade wünschenswert!

Es ist übrigens keine Definition notwendig:class Guard : private Uncopyable { private: Mutex mutex; private: static void* operator new( size_t size ); static void operator delete( void* p ); public: Guard() { mutex.Lock(); } ~Guard() { mutex.Unlock(); } };grüße
-
Tip: ich würde eher im ctor die thread ID ermitteln, und im dtor checken (assert) dass es der gleiche thread ist.
Den überladenen operator new kannst du halt immer aushebeln, brauchst ja nur eine Klasse/Struct machen die ein "Guard" Objekt als Member enthält, und diese Klasse/Struct dann dynamisch anlegen.
p.S.: nenn das Ding nicht Guard, nenn es Lock oder ScopedLock
-
großer fehler !
new ohne nothrow muss eine exception werfen
new mit nothrow hast du noch nicht definiert
-
@r0nny:
Ich brauche keine Exception werfen, weil ein dynamisches Anlegen dieser Klasse schon zur Compilezeit verboten wird.....
Die Operatoren sind "leer" implementiert, damit ich sie als private deklarieren kann.
was ich nicht erwähnte, ist dass der Default Konstruktor private ist, und nur aus meiner einen (anderen) Klasse (friend class von "guard") aufgerufen werden kann. Ich wollte es nicht zu kompliziert beschreiben, da es für das eigentliche Problem nicht relevant ist....
Stimmt ich muss das Kopieren auch unterbinden...
Die Klasse soll nicht von zig Leuten benutzt werden, sondern nur von mir und einem Kollegen und uns die Arbeit ein wenig erleichtern, bzw. uns kontrollieren.
Ich müsste es schon richtig drauf anlegen, diese Klasse falsch zu benutzen....
Warum soll ich die Thread ID ermitteln? Das habe ich nicht verstanden?
-
Ein Mutex ist schon das korrekte Sperrobjekt! Weiß nich wie du diesen implmentierst, du könntest höchstens (falls du Windows benutzt und das Sperren nur für einen Prozess verfügbar sein soll) kritische Bereiche (Critical Sections) als Mutexersatz verwenden.
Sonst passt das schon!grüße
-
@paddy@work : Sorry, war etwas unklar... nur bei DEBUG Builds mache ich das (und würde ich das empfehlen) die Thread ID zu ermitteln und im dtor zu checken. Warum? Ganz einfach weil es keine Möglichkeit gibt "new" zu verhindern - egal was man alles private macht.
Wenn dann jmd. Mist baut indem er ein "Gurad" Objekt in einem Thread konstruiert, und in einem anderen zerstört, dann fliegt dort ein assert(). Ich finde das praktisch.
Dafür spare ich mir eben den Tanz mit privaten Konstruktoren und überladenem new etc.
-
@David_pb:
Ich nutze die Mutexes aus dem ACE Framework.
Unter Linux / Unix sind es Mutexes und unter Windows Critical Sections.@hustbaer:
Stimmt ist eine gute Idee.
Aber wieso kann ich das new nicht verhindern?
Ich habe gestern versucht ein Objekt mit new anzulegen und der Compiler spcukt definitiv einen Fehler aus.Hintergrund der ganzen Sache ist, dass es in meinem System drei Subsysteme und eine Ablaufsteuerung gibt. Die Subsyssteme sollen modular aufgebaut werden, so dass nur die Ablaufsteuerung die Systeme kennt. Temporär bekommen zwei der Subsysteme Zugriff auf das eine, welches ich durch die Guardklasse schützen möchte. Diese beiden Klassen sind friend Klassen vom Guard und dürfen ihn anlegen (private default constructor). Über eine Vererbung kommt man nicht an den Guard, da die (neu/ fremd erstellte) abgeleitete Klasse kein friend ist und somit den privaten Construktor nicht aufrufen darf.
Es soll wie bereits gesagt eigentlich eine Hilfestellung für mich und meinen Kollegen sein, dass wir nirgends vergessen das Mutex wieder frei zu geben und in ein Deadlock laufen. Das System muss sehr robust sein. Ich könnte auch die "richtigen" Guards aus ACE nehmen, allerdings will ich ja auch noch den Zugriff auf das zu schützende Subsystem verwalten und dass können die ACE guards natürlich nicht.
Der Begriff Scoped Lock würde für das Verhalten mit den Mutex passender sein, aber da die Klasse nicht nur den threadsicheren Zugriff, sondern auch noch den Zugriff im Allgemeinen verwaltet (bzw. schützt) habe ich mich für Guard entschieden. Der richtige Name lautet Subsystemname_Guard und symbolisiert, dass er das Subsystem beschützt
-
David_pb schrieb:
Nur statische Objekte sind aber nicht gerade wünschenswert!

Es ist übrigens keine Definition notwendig:class Guard : private Uncopyable { private: Mutex mutex; private: static void* operator new( size_t size ); static void operator delete( void* p ); public: Guard() { mutex.Lock(); } ~Guard() { mutex.Unlock(); } };grüße
Das sieht aber falsch aus. In der Klasse ist ein Mutex-Objekt. Es sieht so aus, daß für jedes Guard-Objekt ein eigener Mutex erzeugt wird. Damit würde die Guard-Klasse aber nicht funktionieren. Das Mutex-Objekt muß auf jeden Fall unabhängig vom Guard sein. Ich würde (bzw. tue es in meiner Mutex/Guard-Implementierung) den Mutex als Referenz an den Konstruktor übergeben. Etwa so:
class Guard { Mutex& mutex; public: Guard(Mutex& mutex_) : mutex(mutex_) { mutex.lock(); } ~Guard() { mutex.unlock(); } };Verwendet wird das ganze so:
void f() { static Mutex mutex; Guard guard(mutex); // hier ist der geschützte Bereich }Als zusätzliches Feature kannst Du den Guard noch mit einer unlock-Methode ausstatten, um den Lock früher frei zu geben. Dann benötigst Du noch einen flag, ob der Mutex gelockt ist oder nicht, so daß er im Destruktor nicht nochmals frei gegeben wird.
Tntnet
-
Das Mutex ist in der Ablaufsteuerung und ist über eine private Methode erreichtbar. Die Guardklasse ist friend von der Ablaufsteuerung. Die Ablaufsteuerung ist ein Singleton.
@tntnet:
Wenn die Klasse lediglich das (ent-)sperren des Mutexes regeln soll, gebe ich Dir Recht. Dann würde ich es auch so machen wie Du.
Allerdings muss die "Guard" Klasse auch noch Referenzen auf das Subsystem liefern. In dieser Konstellation brauche ich keine für diverse Mutexes wiederverwendbare Variante.Ich wollte das Codebespiel ursprünglich sehr einfach halten, damit man das eigentliche Problem (Verbieten des dynamischen Anlegens von Objekten dieser Klasse) sehen kann.
-
paddy@work schrieb:
@hustbaer:
Aber wieso kann ich das new nicht verhindern?Wenn
Guard g(Whatever());geht, dann geht auch
struct G2 { G2() : g(Whatever()) { } Guard g; }; G2* g2 = new G2();Klar was ich meine?