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::vector
或 std::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);
}
我遇到了 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::vector
或 std::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);
}