Gegen Internetzensur
Stoppt die Vorratsdatenspeicherung! Jetzt klicken & handeln!Willst du auch bei der Aktion teilnehmen? Hier findest du alle relevanten Infos und Materialien:
  • Flickr Photos

    www.flickr.com
7. Dez
Son

Singletons und Thread-Locks via boost

Na das war jetzt eine schwerere Geburt.

In C# ist es mit der Threadsynchronisierung ja nun wirklich nicht umständlich: Einmal:

  1. private static readonly object lockObject = new object();

und dann nur noch:

  1. lock( lockObject ) {
  2.      //… Logik hier …
  3. }

Der Lock wird automatisch aufgehoben, wenn der Scope verlassen wird.

Nun stand ich vor dem Problem, in C++ eine Singletonklasse erstellen zu wollen. Die Instanz selbst wollte ich per boost::shared_ptr speichern und von dort an durch meine GetInstance()-Funktion lediglich boost::weak_ptr an die tatsächlichen Nutzer verteilen.
Da shared_ptr allerdings nicht genullt werden können, kam eine weitere Variable hinzu, die angibt, ob die Singletoninstanz bereits erstellt wurde oder nicht.
Um nun (jedenfalls rudimentäre) Threadsicherheit zu gewährleisten, muss jedoch sichergestellt werden, dass das Testen von ‚isInitialized‘ und das tatsächliche Initialisieren atomisch passiert – ein Lock muss her. Der dafür benötigte Semaphor, bereitgestellt über einen boost::mutex, muss dann dafür allerdings ebenfalls statisch sein.

Nun nahm ich an, das Problem ließe sich über eine einfache, statische Variablenzuweisung à la
boost::mutex Singleton::lockObject = boost::mutex(); lösen – aber Pustekuchen!
Hier wird implizit der Copy-Konstruktor aufgerufen, und der ist bei boost::mutex leider privat.
Was mich nun dazu brachte, den Mutex selbst mit einem shared_ptr zu verwalten. Damit sieht das Horrorkonstrukt nun also wie folgt aus:

  1. #include <boost/thread/mutex.hpp>
  2. using namespace boost;
  3.  
  4. // Die Singleton-Klasse
  5. class Singleton {
  6. private:
  7.     // Konstruktor und Copy-Konstruktor privat
  8.     Singleton();
  9.     Singleton(const Singleton&);
  10.  
  11. public:
  12.     // Zugriff auf die Singleton-Instanz
  13.     static weak_ptr<Singleton> GetInstance();
  14.  
  15.     // Vernichtet die Singleton-Instanz
  16.     static void Destroy();
  17.  
  18. private:
  19.     // Gibt an, ob die Klasse initialisiert wurde
  20.     static bool isInitialized;
  21.  
  22.     // Das Lock-Objekt
  23.     static mutex lockObject;
  24.  
  25.     // Die Singleton-Instanz
  26.     static shared_ptr<Singleton> instance;
  27. };

Und die Implementierung:

  1. // Initialisieren der statischen Variablen
  2. bool Singleton::isInitialized = false;
  3. mutex Singleton::lockObject;
  4. shared_ptr<Singleton> Singleton::instance =
  5.                               shared_ptr<Singleton>();
  6.  
  7. Singleton::Singleton() { /* Initialisierung */ }
  8. Singleton::Singleton(const Singleton&) {}
  9.  
  10. // Liefern und, falls nötig, erzeugen der Instanz
  11. weak_ptr<Singleton> Singleton::GetInstance() {
  12.     mutex::scoped_lock lock( lockObject );
  13.     if( !isInitialized )
  14.          instance = shared_ptr<Singleton>( new Singleton() );
  15.     isInitialized = true;
  16.     return weak_ptr( instance );
  17. }
  18.  
  19. // Liefern und, falls nötig, erzeugen der Instanz
  20. void Singleton::Destroy() {
  21.     mutex::scoped_lock lock( lockObject );
  22.     if( isInitialized ) instance.reset()
  23.     isInitialized = false;
  24. }

Und, natürlich, nicht zu vergessen, dass dann noch gegen boost_thread gelinkt werden muss.

edit: Danke an Jan-Nik (siehe Kommentare) für die Rettungsaktion


Warning: require(/www/htdocs/v026730/weblog/wp-content/themes/drexl/comments.php): failed to open stream: Permission denied in /www/htdocs/v026730/weblog/wp-includes/comment-template.php on line 1471

Fatal error: require(): Failed opening required '/www/htdocs/v026730/weblog/wp-content/themes/drexl/comments.php' (include_path='/www/htdocs/v026730/_pear/PEAR') in /www/htdocs/v026730/weblog/wp-includes/comment-template.php on line 1471