为多线程环境包装c ++ new / delete的安全/好方法

时间:2018-03-07 00:12:04

标签: c++ malloc interrupt new-operator delete-operator

我遇到了在不同线程(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);
}

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

是否有某种方法可以确保调用构造函数/析构函数,而无需返回包装每个调用?

1 个答案:

答案 0 :(得分:2)

我假设您处于无法使用容器智能指针的环境中。否则,我建议您返回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);
}