2017-03-01 2 views
-2

Ich habe einige Bibliothekscode, der manchmal Multithread ausgeführt werden muss, aber häufiger Singlethread. Es ist eine Menge kleiner Routinen, die sehr häufig aufgerufen werden. Frühere Erfahrung und Profilerstellung zeigen, dass zusätzliche Verzögerungen die Leistung beeinträchtigen können, daher möchte ich unnötige Gemeinkosten vermeiden.C++ 03 Nullzeiger gegen Null Objektmuster: Auswirkungen auf die Leistung

Ich kann keine separate Instanz der Bibliothek für Single-und Multithread-Verwendung bereitstellen, noch kann ich einen Thread-sicheren Wrapper die Single-Thread-Version bereitstellen. Diese beiden Einschränkungen sind auf das Design der Bibliothek zurückzuführen.

Meine bevorzugte Methode, die Routinen zu schützen, wenn Multithread ausgeführt wird, ist die Verwendung eines Mutex mit Gültigkeitsbereich. Mein erster Gedanke war in Richtung this SO answer.

Die meiste Zeit werden die Routinen jedoch single-threaded ausgeführt, und ich mag den Overhead der Nullzeigerüberprüfung nicht. Dies wird auf einem sehr langsamen ARM9-Prozessor ausgeführt und jeder Zyklus zählt.

In der Praxis werde ich wahrscheinlich mit dem Nullzeiger-Check und Profil gehen, um zu sehen, was es kostet, aber ich frage mich, ob es einen besseren Weg gibt. Zum Beispiel das Null-Objekt-Muster oder die Bibliothek, die einen Callback aufruft.

Antwort

3

Ich habe das Gefühl, dass hier einige Informationen fehlen, um wirklich die beste Antwort zu geben, aber ich sehe keinen Grund, Zeiger hier zu verwenden. Vermutlich rufen Sie einen Bibliothekscode an, sagen wir, es handelt sich um eine Funktion namens void foo(int). Sie können diesen Code nicht ändern und er ist nicht Thread-sicher. Aber du kannst deinen Code ändern, richtig? Stattdessen Code aufzurufen, rufen Sie einen Wrapper um foo:

template <class M> 
void foo_wrapper(M& mutex, int x); { std::lock_guard(mutex); foo(x); } 

Jetzt können Sie einfach einen trivialen no-op-Mutex schreiben:

struct NoMutex { 
    void lock() {} 
    bool try_lock() { return true; } 
    void unlock() {} 
}; 

std::mutex m1; 
NoMutex m2; 
foo_wrapper(m1, 0); // thread safe 
foo_wrapper(m2, 0); // thread unsafe 

Da die Typen mit dem Compiler bekannt sind, die zweite Anruf an foo_wrapper wird überhaupt keinen Overhead haben.

Verwandte Themen