Can I add a function attribute to prevent re-launching?

At the moment, I have some functions that look like this:

private bool inFunction1 = false; public void function1() { if (inFunction1) return; inFunction1 = true; // do stuff which might cause function1 to get called ... inFunction1 = false; } 

I would like to declare them as follows:

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

Is there an attribute that I can add to a function to prevent re-entry? If not, how can I do this? I have heard of AOP attributes that can be used to add code before and after function calls; Do they fit?

+6
function c # attributes reentrancy reentrant
source share
9 answers

Instead of using bool and installing it directly, try using long and the Interlocked class:

 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 } 

This will make the flow check safe.

+14
source share

Without building and rewriting IL, there is no way to create a custom attribute that modifies the code as you describe.

I suggest you use the delegate-based approach instead, for example. for functions of one argument:

 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; } }; } 

This method transfers the function for wrapping (provided that it corresponds to Func <TArg, T> - you can write other options or a completely general version with great effort) and an alternative function for calling in cases of re-entry. (An alternative function may throw an exception or return immediately, etc.). Then, in all the code where you usually call the passed method, you call the delegate returned by WrapAgainstReentry ().

+5
source share

You can create a PostSharp attribute to check if the method name is in the current stack trace

  [MethodImpl(MethodImplOptions.NoInlining)] private static bool IsReEntry() { StackTrace stack = new StackTrace(); StackFrame[] frames = stack.GetFrames(); if (frames.Length < 2) return false; string currentMethod = frames[1].GetMethod().Name; for (int i = 2; i < frames.Length; i++) { if (frames[i].GetMethod().Name == currentMethod) { return true; } } return false; } 
+4
source share

You may find that you can use PostSharp to accomplish this - along with Anthony's suggestions for using try / finally. It will probably be dirty. Also consider whether you want re-intervention to be included in the stream or for each instance. (Can multiple threads invoke in a method to start or not?)

There is nothing of the kind in the structure itself.

+2
source share

There is no such predefined attribute. You can create new attributes, but that will not help you. The problem is that the user attribute prevents the method from being called again, which I believe is not feasible.

The lock statement is not what you want, as it will cause the lock and wait, and not return immediately.

PS: use try ... finally block in the above example. Otherwise, if an exception is thrown in the middle of the function, inFunction1 will be left true, and all calls will be returned immediately.

eg.

 if (inFunction1) return; try { inFunction1 = true; // do stuff which might cause function1 to get called ... } finally { inFunction1 = false; } 
+1
source share

If this is for Thread security, you should be careful with this variable.

Perhaps another thread may enter the function and pass the check before the first thread sets the variable.

Make sure it is marked as volatile:

 private volatile bool inFunction1 = false; 
+1
source share

This thread is a bit outdated, but I thought it would be worth bringing it to 2012, because this problem still exists (more or less). I was able to solve this problem using proxy objects generated using Reflection.Emit (specifically using LinFu.DynamicProxy ). The LinFu article is older than this article, so I assume that everything she discusses matters when asked (and still somehow today).

I used LinFu because I already used it for other purposes, but I'm sure that some of the other DynamicProxy infrastructures available to you will work for you (for example, Castle.DynamicProxy), or you can roll them based on Reflection.Emit (not for those with a poor location). They provide a mechanism that fills most of the AOP role while maintaining control over your code.

+1
source share

I do not think it will be possible.

The closest will be the Synchronized attribute, but this will block all subsequent calls.

0
source share

You might want to avoid re-entry by changing your design so that it never calls function1 () until the previous call completes. It seems to me that the layer is missing from function1 ().

0
source share

All Articles