2009-08-26 14 views
9

Für klassenspezifische new_handler-Implementierung stieß ich auf das folgende Beispiel in Buch "effektive C++". Dies scheint ein Problem in Multithread-Umgebungen. Meine Frage ist, wie man in Multithread-Umgebungen klassenspezifischen new_handler erreicht.mit Klasse spezifische set_new_handler

void * X::operator new(size_t size) 
{ 
    new_handler globalHandler =    // install X's 
    std::set_new_handler(currentHandler); // handler 
    void *memory; 
    try {          // attempt 
     memory = ::operator new(size);   // allocation 
    } 
    catch (std::bad_alloc&) {     // restore 
     std::set_new_handler(globalHandler);  // handler; 
     throw;         // propagate 
    }           // exception 
    std::set_new_handler(globalHandler);  // restore 
               // handler 
    return memory; 
} 

Antwort

4

Sie haben Recht. Dies ist wahrscheinlich nicht threadsicher. Sie könnten einen alternativen Ansatz zu prüfen, wie die nothrow version of new stattdessen mit:

void* X::operator new(std::size_t sz) { 
    void *p; 
    while ((p = ::operator new(sz, std::nothrow) == NULL) { 
    X::new_handler(); 
    } 
    return p; 
} 

Dies wird dazu führen, dass klassenspezifische Handler aufgerufen werden, wenn die Speicherzuordnung fehlschlägt. Ich würde das nicht tun, bis Sie wirklich alle Kopfschmerzen verstehen, die das Überladen operator new umgeben. Lesen Sie insbesondere den zweiteiligen Artikel von Herb Sutter To New, Perchance To Throw, Part 1 und Part 2. Interessanterweise sagt er, die nothrow Version zu vermeiden ... hmmm.

0

C++ weiß (noch) nicht, welche Threads sind. Sie müssen zu Ihrem Compiler/C++ - Standard Bibliothek/Betriebssystem/Thread-Bibliothek Handbücher gehen, um eine thread-sichere Möglichkeit, dies zu tun, oder wenn es sogar möglich ist, zu bestimmen. Ich würde vorschlagen, dass der neue Handler in der Anwendung wahrscheinlich derselbe sein sollte. Es ist kein sehr flexibler Mechanismus, vielleicht würden Ihre Bedürfnisse besser mit einem Zuweiser oder vielleicht einer Fabrik (Funktion) bedient werden? Was möchten Sie innerhalb des benutzerdefinierten neuen Handlers tun?

0

Vielleicht siehst du es falsch an. Ich glaube nicht, dass es eine Möglichkeit gibt, die gesamte Anwendung von der Zuweisung von Speicher zu beschränken (da ein großer Teil der Speicherzuordnung außerhalb Ihres Codes liegt), der beste Weg wäre, zu kontrollieren, was Sie können - dh die Implementierung des Handlers.

Richten Sie den Handler so ein, dass er am Anfang des Programms eine Instanz einer "OutOfMemoryHandler" -Klasse aufruft (wie Sie es nennen) und das Standardverhalten hat, den vorhandenen Handler aufzurufen. Wenn Sie eine klassenspezifische Behandlung hinzufügen möchten, fügen Sie Ihrem OutOfMemoryHandler ein Verhalten hinzu, indem Sie Ihre bevorzugten C++ - Techniken für dynamisches Verhalten verwenden.

Diese Lösung sollte in einer Single-Threaded-Umgebung funktionieren, aber in einer Umgebung mit mehreren Threads fehlschlagen. Damit es in einer Multithread-Umgebung funktioniert, muss der Aufrufer das Handler-Objekt benachrichtigen, dass es in einem bestimmten Thread arbeitet. Die Übergabe der Thread-ID mit der Klasse wäre ein guter Weg, dies zu tun. Wenn der Handler aufgerufen wird, überprüft er die Thread-ID und bestimmt das auszuführende Verhalten basierend auf der zugeordneten Klasse. Wenn der new() -Aufruf beendet ist, lege einfach die Thread-ID ab, um das korrekte Standardverhalten sicherzustellen (ähnlich wie du es bereits beim Zurücksetzen des Standard-Handlers getan hast).

Verwandte Themen