2016-03-22 3 views
3

Mein Code stürzt regelmäßig auf QNX. Es stürzt mit FehlerStd :: Call_once Lazy Initialisierungsproblem auf QNX

Fehlervariable zu lesen: Speicher kann nicht auf 0x85dd6ac Adresse zugreifen)

bei dem Versuch, std :: map Membervariable von 0x85dd6ac Objekt zuzugreifen, die initialisiert std::call_once mit faul ist.

Initialisierung wird mit dem folgenden Pseudocode durchgeführt:

mutable std::aligned_storage<sizeof(A), alignof(A) >::type m_value; 

void init(A *ptr) 
{ 
    new (ptr) A(); 
} 

inline T* data() const 
{ 
    return reinterpret_cast<A*>(&m_value); 
} 

const A& get() const 
{ 
    std::call_once(m_once_flag, init, data()); 
    return *data(); 
} 

An einem gewissen Punkt, wenn Objekt zurückgegeben von get() den Vorgang zugegriffen wird, abgestürzt ist.

Auf anderen Plattformen wird das Problem nicht reproduziert und es ist sehr schwierig zu debuggen. Aus dem Code kann ich sehen, dass das Objekt nicht nicht initialisiert werden kann und auch an diesem Punkt nicht gelöscht werden kann.

Ich vermute, es kann ein Problem mit std::call_once Implementierung mit Thread-Sicherheit oder Speicherordnung sein. Hat jemand Erfahrung mit std :: call_once auf QNX-Plattform oder Bugs so? Irgendwelche Ideen, wie ich das Problem finden kann?

+0

Verwenden Sie GCC? Wild rate: Die QNX Pthreads-Implementierung unterstützt nur die Verwendung von PTHREAD_ONCE_INIT für statische Objekte, und die Verwendung für ein Datenelement im Typ 'std :: once_flag' funktioniert nicht. Macht es einen Unterschied, wenn Sie ein globales 'std :: once_flag' anstelle von' m_once_flag' verwenden? (Ich weiß, das bedeutet, dass Sie die Init nur einmal ausführen können, nicht einmal pro Objekt, aber es könnte helfen, das Problem aufzuspüren). –

+0

@ Jonathan, es ist "veränderbar", also muss es ein nicht-statisches Datenmitglied sein (was das "m_" Präfix auch stark vorschlägt!) –

+0

warum die Variable nicht in der Karte speichern, nur wenn sie gespeichert werden muss? Ich bekomme es nicht –

Antwort

1

Ich habe die gleiche Erfahrung mit std :: call_once in QNX, aber neben Absturz kann es auch Dead Lock in Multithreading-Anwendung verursachen. Ich schlage vor, das folgende Muster verwenden std :: call_once zu ersetzen:

static std::atomic<bool> once_flag = false; 
if (!once_flag.exchange(true)) 
{ 
    // This part will be executed only once. 
    // ... 
} 

UPDATE Basierend auf Kommentar von fefe diese Lösung nicht die Bedingung der Blockierung der passiven Ausführung (siehe Details auf http://www.cplusplus.com/reference/mutex/call_once/).

Wenn Sie dies auch sättigen müssen, sollten Sie eine komplexere Lösung implementieren. Hier ein Beispiel:

static std::atomic<bool> once_flag = false; 
static std::atomic<bool> once_call_done = false; 
if (!once_flag.exchange(true)) 
{ 
    // This part will be executed only once. 
    // ... 

    once_call_done = true; 
} 
else 
{ 
    // Block until the call once part is running. 
    while(!once_call_done) 
    { 
     sleep(1); 
    } 
} 
+1

Das Problem ist, dass der diesem Block folgende Code ausgeführt werden kann, bevor die Ausführung der Initialisierung abgeschlossen ist. Wenn das Flag geändert wird, bevor die Initialisierung abgeschlossen ist, kann ein anderer Thread feststellen, dass "one_flag" "wahr" ist, bevor die Initialisierung endet. – fefe

+0

Danke, guter Punkt. Ich werde meine Antwort basierend auf Ihrem Kommentar ändern. –

1

Problem wurde mit Std :: Call_once. Es ist ein Fehler in der Implementierung. Temporäres Ersetzen mit Mutex löste das Problem. Hatte nicht mehr Zeit, um in Details zu graben, aber hoffentlich wird diese Information jemandem mit ähnlichem Problem helfen.

Vielen Dank für Ihre Kommentare!

Verwandte Themen