2009-08-26 4 views
9

Per l'implementazione new_handler specifica della classe, ho trovato il seguente esempio nel libro "C++ efficace". Questo problema sembra in ambiente multithread, La mia domanda è come ottenere new_handler specifico della classe in ambiente multithreaded?utilizzando la classe specifica 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; 
} 

risposta

4

Hai ragione. Questo probabilmente non è thread-safe. Si potrebbe prendere in considerazione un approccio alternativo come usare il nothrow version of new invece:

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

Questo farà sì che il tuo gestore specifico della classe per essere chiamato ogni volta che l'allocazione di memoria non riesce. Non lo farei finché non capirai veramente tutti i mal di testa che circondano il sovraccarico operator new. In particolare, leggi l'articolo in due parti di Herb Sutter A nuovo, Perchance To Throw, Part 1 e Part 2. Abbastanza interessante, dice di evitare la versione nothrow ... hmmm.

0

C++ non sa (ancora) quali thread sono. Dovrai passare al tuo compilatore/libreria standard C++/sistema operativo/manuali della libreria di thread per determinare un modo thread-safe per farlo, o se è addirittura possibile. Suggerirei che il nuovo gestore dovrebbe probabilmente essere lo stesso in tutta l'applicazione. Non è un meccanismo molto flessibile, forse le tue esigenze sarebbero meglio servite con un allocatore o forse una fabbrica (funzione)? Cosa stai cercando di fare all'interno del nuovo handler personalizzato?

0

Forse lo stai guardando nel modo sbagliato. Non penso che ci sia un modo per limitare l'intera applicazione dall'allocazione della memoria (dal momento che gran parte dell'allocazione della memoria potrebbe essere al di fuori del tuo codice), quindi il modo migliore per farlo sarebbe controllare quello che puoi, cioè l'implementazione del conduttore.

Setup del gestore di chiamare un'istanza di una classe "OutOfMemoryHandler" (chiamatelo come volete) all'inizio del programma e avere il suo comportamento predefinito per chiamare il gestore esistente. Quando vuoi aggiungere una gestione specifica della classe, aggiungi un comportamento a OutOfMemoryHandler usando le tue tecniche C++ preferite per un comportamento dinamico.

Questa soluzione dovrebbe funzionare bene in un ambiente a thread singolo, ma non funzionerà in un ambiente a più thread. Per farlo funzionare in un ambiente multi-thread è necessario che il chiamante notifichi all'oggetto gestore che sta lavorando in un particolare thread; passare il thread-id con la classe sarebbe un buon modo per farlo. Se il gestore viene chiamato, controlla l'ID del thread e determina il comportamento da eseguire in base alla classe associata. Una volta terminata la chiamata a new(), basta deregistrare l'ID del thread per garantire il comportamento predefinito corretto (proprio come si sta già facendo nel reimpostare il gestore predefinito).

Problemi correlati