2016-04-18 3 views
2

Ich schaue mir ein Stück Code an, der bis vor kurzem funktioniert hat. Grundsätzlich habe ich eine C++ - Klasse, in der ich eine Variable mit einem G_LOCK_DEFINE-Makro beschütze.G_LOCK Verhalten von glib 2.46 zu glib 2.48 geändert?

Der Konstruktor ist in einer separaten CPP-Datei implementiert.

Diese Variable wird in mehreren Funktionen aufgerufen, aber das Prinzip ist immer das gleiche. Nun, wie bereits gesagt, der Code ist in Ordnung und funktionierte in der Vergangenheit auch einwandfrei. Jetzt, seit kurzem, bekomme ich einen Deadlock, wenn ich auf einen G_LOCK-Befehl stoße. Zum Debuggen habe ich das Programm bereits auf nur einen Thread eingeschränkt, um logische Fehler auszuschließen.

Ich habe vor kurzem Update auf Ubuntu 16.04 Beta, die meine glib-Version auf 2.48.0-1ubuntu4 geschoben. Ich habe bereits das Changelog auf relevante Informationen zu G_LOCK überprüft, konnte aber nichts finden. Hat jemand andere lustige Effekte bemerkt, wenn G_LOCK Makros mit der aktuellen Version von glib verwendet wurden? Habe ich hier einige Änderungen übersehen?

Antwort

4

Erstens, alles, was G_LOCK_DEFINE tut, ist eine GMutex Variable erstellen, deren Name den Namen der Variable codiert, die es schützt, z. G_LOCK_DEFINE(mSomeCounter) wird GMutex g__mSomeCounter_lock;. So können wir Ihren Code so etwas wie erweitern:

class CSomeClass { 
    private: 
     gulong mSomeCounter; 
     GMutex g__mSomeCounter_lock; 

    public: 
     CSomeClass(); 
}; 

CSomeClass::CSomeClass() 
{ 
    g_mutex_lock(&g__mSomeCounter_lock); 
    mSomeCounter = 0; 
    g_mutex_unlock(&g__mSomeCounter_lock); 
} 

Das grundlegende Problem ist, dass Sie nicht CSomeClassjede der Mitglieder der Klasse sind initialisiert. Sie werden einige von ihnen im Konstruktor Werte zuweisen, aber Sie initialisieren sie definitiv nicht. Es gibt einen Unterschied zwischen der Zuordnung in geschweiften Klammern, und unter Verwendung einen Initialisierer, wie:

CSomeClass::CSomeClass() : mSomeCounter(0) 

Als Ergebnis der Mutex, die gegen die Variable mit dem Namen erstellt Müll enthalten. Es gibt wahrscheinlich nichts im glib-Code, der sich geändert hätte, um dies zu verursachen. Es ist wahrscheinlicher, dass Änderungen an anderen Bibliotheken das Speicherlayout Ihrer App geändert haben, wodurch der Fehler aufgedeckt wird.

Die glib documentation Hinweise, die Sie g_mutex_init mutexes benötigen:

, die auf dem Stapel zugeordnet wurde, oder als Teil einer größeren Struktur

Sie brauchen nicht zu g_mutex_init mutexes dass :

Es ist nicht notwendig, einen Mutex zu initialisieren, der statisch zugewiesen wurde

Klasseninstanzen sind fast immer nicht statisch zugewiesen.

Sie müssen Ihren Konstruktor reparieren, um sicherzustellen, dass er den Mutex "richtig" initialisiert, z.:

CSomeClass::CSomeClass() 
{ 
    g_mutex_init(&G_LOCK_NAME(mSomeCounter)); 
    G_LOCK(mSomeCounter); 
    mSomeCounter = 0; 
    G_UNLOCK(mSomeCounter); 
} 

TBH, würde ich den Mutex in eine Klasse Halter setzen und sie als Teil davon initialisieren, anstatt die Art und Weise, Sie es tun, um sicherzustellen, dass es initialisiert wird, verriegelt und entriegelt als Teil der Standard-C++ RAII-Semantik.

Wenn Sie eine kleine Haupt Stub verwenden, so etwas wie:

main() { 
    { CSomeClass class1; } 
    { CSomeClass class2; } 
    { CSomeClass class3; } 
} 

und Ihren Code, gibt es eine gute Chance, es trotzdem hängen. (Mein Mac abgestürzt das Beispiel mit:. GLib (gthread-posix.c): Unexpected error from C library during 'pthread_mutex_lock': Invalid argument. Aborting.

einige einfache, beispielsweise nicht Produktion Wrapper mit RAII zu helfen:

class CGMutex { 
    GMutex mutex; 

    public: 
    CGMutex() { 
     g_mutex_init(&mutex); 
    } 

    ~CGMutex() { 
     g_mutex_clear(&mutex); 
    } 

    GMutex *operator&() { 
     return &mutex; 
    } 
}; 

class CGMutexLocker { 
    CGMutex &mRef; 
    public: 
    CGMutexLocker(CGMutex &mutex) : mRef(mutex) { 
     g_mutex_lock(&mRef); 
    } 
    ~CGMutexLocker() { 
     g_mutex_unlock(&mRef); 
    } 
}; 

class CSomeClass { 
    private: 
     gulong mSomeCounter; 
     CGMutex mSomeCounterLock; 

    public: 
     CSomeClass(); 
}; 

CSomeClass::CSomeClass() 
{ 
    CGMutexLocker locker(mSomeCounterLock); // lock the mutex using the locker 
    mSomeCounter = 0; 
} 

Die mSomeCounter Initialisierung stellt sicher, dass der Zähler initialisiert wird, sonst wird es haben Müll