如何检测关键函数中调用的后台函数

use*_*054 7 c++

我正在研究非常大的c ++项目,它具有许多实时关键功能以及许多慢速后台功能.不应从时间关键函数中调用这些后台函数.那么有没有办法检测从关键函数调用的这些后台函数?编译时间会很好,但无论如何我想在这些后台函数之前检测.更多信息,慢速和关键功能都是同一类的一部分,并共享相同的标题.

更多信息,关键函数在非常快的线程(> = 10KHz)下运行较慢,在不同的较慢线程(<= 1KHz)下运行.使用慢函数中的关键部分来保护类成员变量,因为它们都使用相同的类成员变量.这就是在关键功能中调用缓慢功能的原因会降低整体系统性能.这就是我想自动找到所有这些功能而不是手动检查的原因.

谢谢....

Dam*_*mon 3

获得除尼古拉斯·威尔逊提出的编译时检测之外的编译时检测即使不是不可能,也是极其困难的,但假设“背景”确实指的是函数,而不是多个线程(我在问题中没有看到线程的提及,所以我认为这只是一个奇怪的措辞)您可以简单地使用全局标志和储物柜对象,并且或者assert抛出异常。或者,输出调试消息。当然,这只是运行时的——但是您应该能够非常快速地隔离违规者。对于调试版本来说,它的开销也非常低(几乎保证从 L1 缓存运行),而对于发布版本来说则没有。

使用CaptureStackBackTrace,人们应该能够捕获有问题的函数的地址,类似的工具addr2line(或任何 MS 等效工具)可以直接将其转换为代码中的一行。甚至可能有一个 toolhelp 函数可以直接进行此翻译(尽管我不知道)。

所以,像这样的东西(未经测试!)可能会起作用:

namespace global { int slow_flag = 0; }
struct slow_func_locker
{
    slow_func_locker() { ++global::slow_flag; }
    ~slow_func_locker(){ --global::slow_flag; }
};
#indef NDEBUG
  #define REALTIME  if(global::slow_flag) \
  { \
    void* backtrace; \
    CaptureStackBackTrace(0, 1, &backtrace, 0); \
    printf("RT function %s called from %08x\n", __FUNCTION__, backtrace); \
  }
  #define SLOW_FUNC slow_func_locker slow_func_locker_;
#else
  #define REALTIME
  #define SLOW_FUNC
#endif

foo_class::some_realtime_function(...)
{
    REALTIME;
    //...
};

foo_class::some_slow_function(...)
{
    SLOW_FUNC;
    //...
    some_realtime_function(blah); // this will trigger
};
Run Code Online (Sandbox Code Playgroud)

唯一真正的缺点(除了不是编译时)是你必须用任一标记来标记每个慢速和实时函数,但由于编译器无法神奇地知道哪个是什么,所以无论如何都没有太多选择。

请注意,全局“标志”实际上是一个计数器,而不是标志。原因是慢速函数可以立即调用另一个返回并清除标志的慢速函数——现在错误地假设一个快速函数(xgbi 建议的临界区方法在这种情况下可能会死锁!)。计数器可以防止这种情况发生。在存在线程的情况下,也可以替换intstd::atomic_int

编辑:
现在很明显,确实有2 个线程在运行,并且其中一个线程(“快”线程)永远不会调用“慢”函数,这很重要,还有另一个简单的、有效的解决方案(例如使用Win32 API,但也可以使用 POSIX 来完成):

当“快”线程启动时(“慢”线程不需要这样做),将线程 ID 存储在某处,可以是全局变量,也可以是包含所有快/慢函数的对象的成员——任何地方在哪里可以访问:

global::fast_thread_id = GetCurrentThreadId();
Run Code Online (Sandbox Code Playgroud)

用于摆脱“不受欢迎的”函数调用的宏可能如下所示:

#define CHECK_FAST_THREAD assert(GetCurrentThreadID() != global::fast_thread_id)
Run Code Online (Sandbox Code Playgroud)

然后将该宏添加到任何不应从“快”线程调用的“慢”函数中。如果快速线程调用了一个它不能调用的函数,则断言会触发,并且知道哪个函数被调用。

  • @user2409054:所以基本上,你有2个线程,其中一个线程调用慢速函数(并且_也可以_调用快速函数,没有坏处),另一个线程应该_仅_调用快速函数。为此,所提出的解决方案(包括我的)都不起作用。然而,可以通过对计数器使用 TLS 来使其工作。TLS 是必要的,因为否则无法知道哪个线程递增/递减了计数器。同样,互斥量/信号量也不好,因为任何步骤都可能获取它。TLS 是一个轻微的开销,但它只是在调试模式下。 (2认同)