C++中的中断服务例程

Interrupt service routine in C++

本文关键字:服务例程 中断 C++      更新时间:2023-10-16

对于实时嵌入式系统,我试图提供一个中断处理程序,它允许注册任何非静态方法指针(当然还有对象的实例),当中断发生时,它会被调用。

在C中,这很容易做到,例如:

void (*func)(void*) = 0; // <- method to be called goes here
void* instance;          // <- instance for this-call goes here
void InterruptHandler()
{
  func(instance);
}

当然,这符合C++在调用非静态方法时隐式执行的this调用。

然而,C++编译器拒绝将方法指针转换为函数指针(至少我没有找到这样做的方法)——这当然是可以理解的,但在我的情况下会适得其反。

有什么方法可以像在C中那样直接模拟C++这个调用吗?我知道委托,但我的编译器仅限于C++98,没有boost库等;甚至自定义的轻量级实现,例如Sergey Ryazanov的Impossibly Fast C++Delegates,也提供了我希望尽可能避免的一定开销。

方法总是包含一个隐藏的this参数,以提供对被调用对象的访问。要从一个中断处理程序中调用一个类,该类期望C或类似C的调用行为,所列参数和所需参数之间的对应关系为1:1,则必须提供类似C的行为。这意味着没有隐藏参数的自由函数或静态方法。

这意味着,如果不深入研究关于未定义行为的假设,就无法将方法分配给函数指针。

但是,如果对象可用,则可以让静态方法或自由函数调用对象上的方法。

给定

void (*func)(void*)

void *是指向用户提供的控制信息的指针时,简单的解决方案是形式的静态方法或自由函数

void handlerCaller(void* userp)
{
    ISRHandlerClass * handlerp = (ISRHandlerClass *) userp;
    handlerp->isrhandler(); // tiny bit may be lost here to subclass look-up
}

void isrhandler()

实现为执行检查ISRHandlerClassISRHandlerClass的子级需要执行的任何操作

你几乎被handlerCaller或类似的东西卡住了,所以这是你无法避免的开销。其余的取决于您希望ISR接口的通用性

一个简单的通用ISR处理程序基类:

class ISRHandlerClass
{
    public:
        virtual ~ISRHandlerClass()
        {
        }
        // pure virtual to be implemented by specialized handler
        virtual void isrhandler() = 0;  
};

和一个同样简单的实现

class FooHandler: public ISRHandlerClass
{
    public:
        void isrhandler() //override tag if you've got 'em
        {
            // read Foo and store in buffer to be processed by lower priority task
        }  
};

但是,如果你想抛弃泛化而追求速度,就不要考虑子类。如果需要多个处理程序调用程序,则需要为其牺牲空间。

void FooHandlerCaller(void* userp)
{
    FooHandler * handlerp = (FooHandler *) userp;
    handlerp->isrhandler();
}
void BarHandlerCaller(void* userp)
{
    BarHandler * handlerp = (BarHandler *) userp;
    handlerp->isrhandler();
}

template <class TYPE>
void handlerCaller(void* userp)
{
    TYPE * handlerp = (TYPE *) userp;
    handlerp->isrhandler();
}

使用

class FooHandler
{
    public:
        void isrhandler()
        {
            // read Foo and store in buffer to be processed by lower priority task
        }  
};
void (*func)(void*) = handlerCaller<FooHandler>;
FooHandler handler;
void* instance = (void *)&handler;