c – 与原始函数指针和void *相比,std ::函数的性能?

图书馆代码
class Resource 
{
public:
    typedef void (*func_sig)(int,char,double,void*);
//Registration
    registerCallback(void* app_obj,func_sig func)
    {
        _app_obj = app_obj;
        _func = func;
    }

//Calling when the time comes
    void call_app_code()
    {
        _func(231,'a',432.4234,app_obj);
    }
//Other useful methods
private:
    void* app_obj;
    func_sig _func;
//Other members
};

申请编号:

class App
{
public:
    void callme(int,double);
//other functions,members;
};

void callHelper(int i,char c,double d,void* app_obj)
{
    static_cast<ApP*>(app_obj)->callme(i,c,d);
}

int main()
{
    App a;
    Resource r;
    r.registercallback(&a,callHelper);
//Do something
}

以上是回调机制的最小实现.它更冗长,不支持绑定,占位符等,如std :: function.
如果我使用std :: function或boost ::函数为上述用例,会有任何性能缺陷吗?这种回调将在实时应用程序的非常关键的路径中.我听说boost :: function使用虚拟函数做实际的调度.如果没有约束/占位符参与,会被优化吗?

解决方法

我很经常想到自己,所以我开始写一些非常小的基准,试图通过循环的原子计数器来模拟每个函数指针回调版本的性能.

请记住,这些都是对只做一件事的功能的裸露的调用,原子地增加其计数器;

通过检查生成的汇编器输出,您可以发现,一个裸C函数指针循环被编译成3个cpu指令;

C 11的std ::函数调用添加了2个cpu指令,因此在我们的示例中增加了5个.作为一个结论:绝对不用你使用什么方式的函数指针技术,开销差异在任何情况下都非常小.

((但令人困惑的是,分配的lambda表达式似乎运行速度比其他,甚至比C-one更快))

编译示例:clang -o tests / perftest-fncb tests / perftest-fncb.cpp -std = c 11 -pthread -lpthread -lrt -O3 -march = native -mtune = native

#include <functional>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

typedef unsigned long long counter_t;

struct Counter {
    volatile counter_t bare;
    volatile counter_t cxx;
    volatile counter_t cxo1;
    volatile counter_t virt;
    volatile counter_t lambda;

    Counter() : bare(0),cxx(0),cxo1(0),virt(0),lambda(0) {}
} counter;

void bare(Counter* counter) { __sync_fetch_and_add(&counter->bare,1); }
void cxx(Counter* counter) { __sync_fetch_and_add(&counter->cxx,1); }

struct CXO1 {
    void cxo1(Counter* counter) { __sync_fetch_and_add(&counter->cxo1,1); }
    virtual void virt(Counter* counter) { __sync_fetch_and_add(&counter->virt,1); }
} cxo1;

void (*bare_cb)(Counter*) = nullptr;
std::function<void(Counter*)> cxx_cb;
std::function<void(Counter*)> cxo1_cb;
std::function<void(Counter*)> virt_cb;
std::function<void(Counter*)> lambda_cb;

void* bare_main(void* p) { while (true) { bare_cb(&counter); } }
void* cxx_main(void* p) { while (true) { cxx_cb(&counter); } }
void* cxo1_main(void* p) { while (true) { cxo1_cb(&counter); } }
void* virt_main(void* p) { while (true) { virt_cb(&counter); } }
void* lambda_main(void* p) { while (true) { lambda_cb(&counter); } }

int main()
{
    pthread_t bare_thread;
    pthread_t cxx_thread;
    pthread_t cxo1_thread;
    pthread_t virt_thread;
    pthread_t lambda_thread;

    bare_cb = &bare;
    cxx_cb = std::bind(&cxx,std::placeholders::_1);
    cxo1_cb = std::bind(&CXO1::cxo1,&cxo1,std::placeholders::_1);
    virt_cb = std::bind(&CXO1::virt,std::placeholders::_1);
    lambda_cb = [](Counter* counter) { __sync_fetch_and_add(&counter->lambda,1); };

    pthread_create(&bare_thread,nullptr,&bare_main,nullptr);
    pthread_create(&cxx_thread,&cxx_main,nullptr);
    pthread_create(&cxo1_thread,&cxo1_main,nullptr);
    pthread_create(&virt_thread,&virt_main,nullptr);
    pthread_create(&lambda_thread,&lambda_main,nullptr);

    for (unsigned long long n = 1; true; ++n) {
        sleep(1);
        Counter c = counter;

        printf(
            "%15llu bare function pointer\n"
            "%15llu C++11 function object to bare function\n"
            "%15llu C++11 function object to object method\n"
            "%15llu C++11 function object to object method (virtual)\n"
            "%15llu C++11 function object to lambda expression %30llu-th second.\n\n",c.bare,c.cxx,c.cxo1,c.virt,c.lambda,n
        );
    }
}

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...