我可以向函数添加属性以防止重新进入吗?

Sim*_*mon 7 c# attributes function reentrancy

目前,我有一些看起来像这样的功能:

private bool inFunction1 = false;
public void function1()
{
    if (inFunction1) return;
    inFunction1 = true;

    // do stuff which might cause function1 to get called
    ...

    inFunction1 = false;
}
Run Code Online (Sandbox Code Playgroud)

我希望能够像这样声明它们:

[NoReEntry]
public void function1()
{
    // do stuff which might cause function1 to get called
    ...
}
Run Code Online (Sandbox Code Playgroud)

是否有可以添加到函数中的属性以防止重新进入?如果没有,我将如何制作一个?我听说过可以用来在函数调用之前和之后添加代码的AOP属性; 他们会适合吗?

Sea*_*ean 16

不要使用bool并直接设置它,请尝试使用long和Interlocked类:

long m_InFunction=0;

if(Interlocked.CompareExchange(ref m_InFunction,1,0)==0)
{
  // We're not in the function
  try
  {
  }
  finally
  {
    m_InFunction=0;
  }
}
else
{
  // We're already in the function
}
Run Code Online (Sandbox Code Playgroud)

这将使检查线程安全.

  • 您的Win32 api被定义为采用int32,如果您使用C++来定位Win32,则int和long都定义为int32.而且......好吧,你不在乎. (3认同)
  • 没有特别的原因.我用它做了很多Win32编程,并且互锁功能需要很长时间.在上面的例子中使用int不会有任何区别. (2认同)

Bar*_*lly 5

如果没有汇编和IL重写,则无法创建以您描述的方式修改代码的自定义属性.

我建议您使用基于委托的方法,例如,对于单个参数的函数:

static Func<TArg,T> WrapAgainstReentry<TArg,T>(Func<TArg,T> code, Func<TArg,T> onReentry)
{
    bool entered = false;
    return x =>
    {
        if (entered)
            return onReentry(x);
        entered = true;
        try
        {
            return code(x);
        }
        finally
        {
            entered = false;
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

此方法采用函数进行换行(假设它匹配Func <TArg,T> - 您可以编写其他变体,或者更加努力地完全通用的版本)以及在重新进入的情况下调用的备用函数.(备用函数可能抛出异常,或立即返回等)然后,在通常调用传递方法的代码中,调用WrapAgainstReentry()返回的委托.


Ant*_*ony 1

没有预定义这样的属性。您可以创建新属性,但这对您没有帮助。问题是使自定义属性阻止再次调用该方法,我认为这是不可行的。

lock 语句不是您想要的,因为这将导致调用阻塞并等待,而不是立即返回。

PS:在上面的示例中使用 try ...finally 块。否则,如果在函数中间抛出异常,inFunction1 将保留 true 并且所有调用将立即返回。

例如:

if (inFunction1) 
   return;

try
{
  inFunction1 = true;

  // do stuff which might cause function1 to get called
  ...
}
finally 
{
  inFunction1 = false;
}
Run Code Online (Sandbox Code Playgroud)