2009-08-26 12 views
9

Pour une implémentation new_handler spécifique à la classe, je suis tombé sur l'exemple suivant dans le livre "C++ efficace". Cela semble problème dans un environnement multithread, Ma question est de savoir comment réaliser new_handler spécifique à la classe dans un environnement multithread?en utilisant set_new_handler spécifique à la classe

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; 
} 

Répondre

4

Vous avez raison. Ce n'est probablement pas sûr pour les threads. Vous voudrez peut-être envisager une autre approche comme l'utilisation de la place nothrow version of new:

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

Cela entraînera votre gestionnaire spécifique de classe à chaque fois appelé l'allocation de mémoire échoue. Je ne ferais pas cela jusqu'à ce que vous compreniez vraiment tous les maux de tête entourant la surcharge operator new. En particulier, lisez l'article en deux parties de Herb Sutter To New, Perchance To Throw, Part 1 et Part 2. Fait intéressant, il dit d'éviter la version nothrow ... hmmm.

0

C++ ne sait pas (encore) ce que sont les threads. Vous devrez vous tourner vers les manuels de la bibliothèque/du système d'exploitation/de la bibliothèque de threads de votre compilateur/bibliothèque standard C++ pour déterminer un moyen sûr de faire cela, ou si c'est même possible. Je suggère que le nouveau gestionnaire devrait probablement être le même dans toute l'application. Ce n'est pas un mécanisme très flexible, peut-être vos besoins seraient mieux servis avec un allocateur ou peut-être une usine (fonction)? Que cherchez-vous à faire dans le nouveau gestionnaire personnalisé?

0

Peut-être que vous regardez dans le mauvais sens. Je ne pense pas qu'il existe un moyen de limiter l'application entière de l'allocation de mémoire (puisque la plupart de l'allocation de mémoire peut être en dehors de votre code), donc la meilleure façon de le faire serait de contrôler ce que vous pouvez du gestionnaire.

Configurez le gestionnaire pour appeler une instance d'une classe "OutOfMemoryHandler" (appelez-le comme vous voulez) au début du programme et avez son comportement par défaut pour appeler le gestionnaire existant. Lorsque vous souhaitez ajouter une gestion spécifique à une classe, ajoutez un comportement à votre OutOfMemoryHandler en utilisant vos techniques C++ préférées pour le comportement dynamique.

Cette solution devrait fonctionner dans un environnement monothread, mais échouer dans un environnement multithread. Pour que cela fonctionne dans un environnement multithread, vous devez demander à l'appelant de notifier l'objet gestionnaire sur lequel il travaille dans un thread particulier; passer le thread-id avec la classe serait un bon moyen de le faire. Si le gestionnaire est appelé, il vérifie l'ID de thread et détermine le comportement à exécuter en fonction de la classe associée. Lorsque l'appel new() est terminé, désinscrivez simplement l'identificateur de threads pour vous assurer du comportement par défaut correct (comme vous le faites déjà en réinitialisant le gestionnaire par défaut).