Archive for July, 2009

防止函数重入

2009-7-8 23:10 | by 2ndboy

  最近被某人说已经 n 久没有更新过 blog 了,不过最近真的是比较累,情有可原:D 今晚临睡前搞个短篇。

  项目上需要解决一个函数重入的问题,不涉及多线程,就是在一个线程内被 GUI 触发的 Windows Message 导致的函数重入。解决这类问题我们最常用到的招儿就是一个全局/静态的 flag,在函数入口处置 true,在出口处置 false。但具体到我们这个需要进行防重入的函数,出口实在是太多。在每个出口处之前给 flag 置 false 这种烂招儿显然不太优雅,于是利用局部变量生存期的原理实现了个防重入类:

  1. class CAntiReenter
  2.  {
  3.  public:
  4.      CAntiReenter() { ++m_nEnterTimes; }
  5.      ~CAntiReenter() { --m_nEnterTimes; }
  6.  
  7.      bool IsReenter() { return( m_nEnterTimes > 1 ); }
  8.  
  9.  private:
  10.      static int m_nEnterTimes;
  11.  };
  12.  int CAntiReenter::m_nEnterTimes = 0;

用的时候只需要在函数入口处创建一个临时类实例(栈上)即可,有多少出口不必操心,那是编译器会帮我们搞定的事情:

  1. bool foo( int bar )
  2.  {
  3.      CAntiReenter ar;
  4.      if( ar.IsReenter() )
  5.          return( false );
  6.  
  7.      ... ...
  8.  }

为什么要实现这个东西的原因也是解释为什么函数最好保证单出口的一个很好的例子。我们项目里的需求是不需要考虑多线程的,如果要考虑多线程因素的话,下面的这个加强版实现应该是个不错的开始:

  1. class CAntiReenter
  2.  {
  3.  public:
  4.      CAntiReenter() {}
  5.      ~CAntiReenter() { InterlockedDecrement( &m_nEnterTimes ); }
  6.  
  7.      bool IsReenter() { return( InterlockedIncrement( &m_nEnterTimes ) ); }
  8.  
  9.  private:
  10.      static long m_nEnterTimes;
  11.  };
  12.  long CAntiReenter::m_nEnterTimes = -1;