如何在改进的系统上的中断处理程序中安全地使用std :: function?

问题描述

我正在使用STM33F103,并且正在尝试实现一种回调机制,该机制将调用给定对象上的方法来处理中断,到目前为止,我使用以下解决方案:

class Nvic
{
public:
   using function_pointer =void (*)(void);  

   template<typename T>
   static void get_interrupt(int interrupt_number,T* object,void (T::*methode)())
   {
       class_vector[interrupt_number]=reinterpret_cast<Default_class*>(object);
       method_vector[interrupt_number]=reinterpret_cast<default_method_type>(methode);
   }

   static void execute_interrupt(int interrupt_number)
   {
       (class_vector[interrupt_number]->*method_vector[interrupt_number])();
   }
private:
   struct Default_class{void default_method();};
   using default_method_type =void(Default_class::*)(void);

   static inline Default_class* class_vector[NUMBER_OF_INTERRUPTS];
   static inline default_method_type method_vector[NUMBER_OF_INTERRUPTS];
}

extern "C"
{
void Some_ISR(void) __attribute__ ((interrupt));    
void Some_ISR(void){Nvic::execute_interrupt(2);}
}

如果某个对象想要将中断绑定到自身:

class Some_class
{
public:
    Some_class(int peripherial_iterrupt)
    {
         Nvic::get_interrupt(peripherial_iterrupt,this,&Some_class::my_interrupt);
    }

private:
    my_interrupt();

};

但是我想基于std::function来实现这一点,不幸的是事实证明std::function can dynamically allocate memory并不是可重入的。 那么,有什么方法可以确保std::function是中断安全的吗?

也许使用分配器可以解决问题,如果我提供std::function,我的自定义分配器将在某些静态内存缓冲区中分配内存,就不会出现中断堆损坏的问题。

或者如果我提供newlib-nano __malloc_lock__mallock_free函数,那么堆内存分配将是中断安全的。

它也可能允许我在中断安全的环境中使用其他STL容器和算法,例如:

class Some_interface :private Some_peripherial
{
public:
    Some_interface(int peripherial_number) :Some_peripherial(peripherial_number)
    {
        int interrupt_number =peripherial_number;   
        Nvic::get_interrupt(interrupt_number,&Some_interface::interrupt_routine);
    }
    void send_data(void* buff,size_t size)
    {
        for(size_t i=0;i<size;i++)
        {
            data_to_send.push_back((uint8_t)buff[i]);
        }
    }

    void set_all_data_send_callback(std::function<void(void)> f){all_data_send_callback=f;}

private:
    std::vector<uint8_t> data_to_send;
    std::function<void(void)> all_data_send_callback;

    void interrupt_routine()
    {
        if(data_to_send.empty()){if(all_data_send_callback)all_data_send_callback();};
        else
        {
            Some_peripherial::send(data_to_send.back());
            data_to_send.pop_back();
        }       
    }
};

class Timer_task :private Timer_peripherial
{
public:
    Timer_task(int peripherial_number) :Timer_peripherial(peripherial_number)
    {
        int interrupt_number =peripherial_number;   
        Nvic::get_interrupt(interrupt_number,&Timer_task ::on_interrupt);
        Timer_peripherial::set_interrupt_on_evry_10ms();
    }

    template<typename T>
    static void set_task(T* object,void (T::*methode)())
    {
        task =std::bind(std::mem_fn(methode),object);
    }

private:
    std::function<void(void)> task;
    void on_interrupt()
    {
        if(task) task();
    }
};

Some_interface interface_0{0};
Some_interface interface_1{1};

const char global_message[] ="global_message";
Timer_task timer_task{interface_1.send_data((void*)global_message,strlen(global_message))};


int main()
{

    const char message_0[] ="123456";
    const char message_1[] ="1256";
    while(1)
    {
        interface_0.send_data((void*)message,strlen(message));
        interface_1.send_data((void*)message,strlen(message));
        delay();
    }
}

在data_to_send中从main填充,并且还形成从另一个中断调用的其他方法

如果需要,我们还可以设置all_data_send_callback。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)