9

对于特定于类的 new_handler 实现,我在“有效 c++”一书中遇到了以下示例。这在多线程环境中看起来有问题,我的问题是如何在多线程环境中实现类特定的 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;
}
4

3 回答 3

4

你是对的。这可能不是线程安全的。您可能需要考虑另一种方法,例如使用以下nothrow版本new

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

这将导致在内存分配失败时调用特定于类的处理程序。在您真正了解有关超载的所有令人头疼的问题之前,我不会这样做operator new。特别是,请阅读 Herb Sutter 的两部分文章To New, Perchance To Throw, Part 1Part 2。有趣的是,他说要避免这个nothrow版本......嗯。

于 2009-08-26T02:32:35.227 回答
0

C++(还)不知道线程是什么。您将不得不求助于您的编译器/C++ 标准库/操作系统/线程库手册来确定执行此操作的线程安全方式,或者是否可行。我建议新的处理程序在整个应用程序中应该是相同的。这不是一个非常灵活的机制,也许使用分配器或工厂(函数)会更好地满足您的需求?您希望在自定义新处理程序中做什么?

于 2009-08-26T02:19:14.110 回答
0

也许你看错了。我认为没有任何方法可以限制整个应用程序分配内存(因为大部分内存分配可能在您的代码之外),因此最好的方法是控制您可以控制的内容 - 即实现的处理程序。

将处理程序设置为在程序开始时调用“OutOfMemoryHandler”类的实例(随便调用它),并使其默认行为调用现有处理程序。当您想要添加特定于类的处理时,请使用您最喜欢的 C++ 技术将行为添加到 OutOfMemoryHandler 以实现动态行为。

这个解决方案应该在单线程环境中运行良好,但在多线程环境中会失败。要使其在多线程环境中工作,您需要让调用者通知处理程序对象它正在特定线程中工作;将线程 ID 与类一起传递将是一个很好的方法。如果调用了处理程序,则它会检查线程 ID 并根据关联的类确定要执行的行为。当 new() 调用完成时,只需取消注册线程 ID 以确保正确的默认行为(就像您在重置默认处理程序时已经在做的那样)。

于 2009-08-26T03:06:23.660 回答