Safe/good 为多线程环境包装 c++ new/delete 的方法

Safe/good way to wrap c++ new/delete for multi-threaded environment

我遇到了 new/deletes 发生在不同线程 (TI F28379D) 上的一些问题,如果在分配或删除过程中发生中断,这些问题会导致程序锁定。我不想用禁用和启用中断的宏来包装 new/delete 的每个实例,因为它感觉像是很多重复代码。我的解决方案是创建两个在 new/delete.

周围具有适当宏的函数
void *create_array_pointer(uint16_t count, size_t size, char *variable_name) {
    //create the array (inside where interrupts are disabled
    uint16_t interrupt_settings = __disable_interrupts();
    void *ptr = new uint16_t[count*size];
    __restore_interrupts(interrupt_settings);
    check_allocation_throw_error(ptr, variable_name);
    return ptr;
}

void delete_array_pointer(void *ptr) {
    uint16_t interrupt_settings = __disable_interrupts();
    delete[] ptr;
    ptr = NULL;
    __restore_interrupts(interrupt_settings);
}

这适用于基本类型。但是,我今天意识到这对于具有默认 constructors/destructors 的 c++ 类 来说是一个糟糕的解决方案,因为永远不会自动调用构造函数或析构函数。

有没有什么方法可以确保 constructors/destructors 被调用,而不用返回包装每个调用?

我假设您处于无法使用 容器智能指针 的环境中。否则我建议返回 std::vectorstd::unique_ptr.

您可以使用模板来保留您正在创建的对象的 类型 ,同时仍然是 通用

您可能还需要考虑一种 RAII 方式来管理您的 中断 因为它们将是异常安全的并且通常更安全和更容易:

template<typename T>
void check_allocation_throw_error(T*, char const*) {}

// This will disable interrupts on creation and re-enable them
// when it goes out of cope. This means if you reach the end
// of the function OR if an exception is thrown the interrupts
// will be re-enabled regardless.
class interrupt_disabler
{
public:
    interrupt_disabler(): settings(__disable_interrupts()) {}
    ~interrupt_disabler() { __restore_interrupts(settings); }

private:
    interrupt_disabler(interrupt_disabler const&) {}
    interrupt_disabler& operator=(interrupt_disabler const&) { return *this; }

    uint16_t settings;
};


template<typename T>
T* create_array_of(uint16_t count, char const* variable_name)
{
    T* ptr = 0;

    // create a scope where interrupts are disabled
    {
        interrupt_disabler lock(); // enabled at end of scope OR if new throws
        ptr = new T[count];
    }
    // interrupts enabled automatically here

    check_allocation_throw_error(ptr, variable_name);

    return ptr;
}

template<typename T>
void delete_array(T* ptr)
{
    interrupt_disabler lock(); // enabled at end of scope
    delete[] ptr;
}

struct MyType {}; // any old type

int main()
{
    MyType* mytype = create_array_of<MyType>(10, "wibble");

    delete_array(mytype);
}