views:

231

answers:

3

For class specific new_handler implementation, i came across the following example in book "effective c++". This looks problem in multithreaded environment, My Question is how to achieve class specific new_handler in multithreaded environment?

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

C++ doesn't (yet) know what threads are. You'll have to turn to your compiler/C++ standard library/operating system/thread library manuals to determine a thread safe way to do this, or if it is even possible. I would suggest that the new handler should probably be the same across the application. It's not a very flexible mechanism, perhaps your needs would be better served with an allocator or perhaps a factory (function)? What are you looking to do inside the custom new handler?

Logan Capaldo
+1  A: 

You're right. This is probably not thread safe. You might want to consider an alternative approach like using the nothrow version of new instead:

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

This will cause your class-specific handler to be called whenever memory allocation fails. I wouldn't do this until you really understand all of the headaches surrounding overloading operator new. In particular, read Herb Sutter's two part article To New, Perchance To Throw, Part 1 and Part 2. Interestingly enough, he says to avoid the nothrow version... hmmm.

D.Shawley
A: 

Perhaps you're looking at it the wrong way. I don't think there is any way to limit the whole application from allocating memory (since much of the memory allocation may be outside of your code), so the best way to do it would be to control what you can - i.e. the implementation of the handler.

Setup the handler to call an instance of a "OutOfMemoryHandler" class (call it what you will) at the start of the program and have its default behaviour to call the existing handler. When you want to add class specific handling, add a behaviour to your OutOfMemoryHandler using your favourite C++ techniques for dynamic behaviour.

This solution should work well in a single-threaded enviroment, but will fail in a multi-threaded environment. To make it work in a multi-threaded environment you need to have the caller notify the handler object that it is working in a particular thread; passing the thread-id with the class would be a good way to do this. If the handler is called, then it checks the thread-id and determines the behaviour to execute based upon the associated class. When the new() call is finished simply deregister the thread-id to ensure the correct default behaviour (much like you are already doing in resetting the default handler).

PinkTriangles