【问题标题】:How to check if a function is calling back to itself如何检查函数是否正在回调自身
【发布时间】:2019-05-16 04:58:13
【问题描述】:

假设我们在库中有一个 C 函数 funA,在 funA 中它会调用一些其他函数 funB、funC 等。 funB 和 funC 可能会回调 funA。所以问题是: 是否可以在 funA 内部检测到这种情况,例如:

void funA(void) {
    if (...) {
         // Calling back to funA
    }

}

结论

  • 在单线程环境中,静态/全局变量可以工作。
  • 在多线程环境中,必须依赖 TLS 支持。
  • 没有任何答案可以仅通过语言 (C) 级别的技巧来实现这一目标

【问题讨论】:

  • 是的,有一个静态标志。在函数的开头检查它,设置它然后在函数返回之前清除它。
  • @WeatherVane 这不会起作用 funA 可以被不同的线程调用,不是吗?
  • 那么请把这个要求放在问题中。已经有一些库函数不是线程安全的。
  • 你为什么不让它接受一个参数?
  • @mnistic 你能解释一下这是什么样的吗?

标签: c recursion computer-science cpu-architecture software-design


【解决方案1】:

这可以通过静态标志来完成。

当函数被调用时,如果标志没有设置,则设置它并继续,否则立即返回。然后在函数结束时,清除标志以便再次输入。

void funcA(void) 
{
    static int callback = 0;

    if (callback) return;
    callback = 1;
    ...
    callback = 0;
}

如果这需要单独在多个线程中工作,您可以将变量声明为_Thread_local 而不是static。

【讨论】:

  • 认为这可能是现在最好的答案。谢谢@dbush
【解决方案2】:

如果只是单次调用,则可以在调用此函数后设置一个全局/静态标志,并在开始时检查它。或者为了消除单次调用的限制,您可以在函数返回之前重置此标志。 类似的东西:

void funA(void) {
    static bool used = false;
    if (used)
    {
        printf("It is used!\n");
    }
    used = true;

    // .... Do stuff here, including possible recursion

    used = false;
}

注意 - 这不适用于多线程 - 此函数不可重入..

【讨论】:

    【解决方案3】:

    也许你可以用另一种方法来识别调用者:

    void func_a(void *ptr);
    void func_b(void);
    void func_c(void);
    
    void func_a(void *caller)
    {
        if(caller == func_a)
        {
            printf("called from func_a\n");
            return;
        }
        if(caller == func_b)
        {
            printf("called from func_b\n");
            return;
        }    
        if(caller == func_c)
        {
            printf("called from func_c\n");
            return;
        }    
        if(caller == NULL)
        {
            printf("called from somewhere elese - going to call myself\n");
            func_a(func_a);
        }
    }
    
    void func_b()
    {
        func_a(func_b);
    }
    
    void func_c()
    {
        func_a(func_c);
    }
    
    int main()
    {
        func_b();
        func_c();
        func_a(NULL);
    
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      使用间接级别,您甚至可以计算函数被调用的次数:

      void func( int count )
      {
          printf( "Count is %d\n", count );
          if ( ... ) // no longer want to recurse...
          {
              return;
          }
          func( count + 1 );
      }
      
      // wrap the actual recursive call to hide the parameter
      void funA()
      {
          func( 0 );
      }
      

      这样,它是完全线程安全的。如果您不想传递包装函数或参数,可以使用thread-specific storage。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-04-11
        • 1970-01-01
        • 2011-09-08
        • 2019-05-07
        • 1970-01-01
        • 1970-01-01
        • 2014-02-18
        相关资源
        最近更新 更多