Do I need to connect an anonymous delegate?

I call CopyFileEx from a C # application with an anonymous delegate, which is passed to the LPPROGRESS_ROUTINE parameter to receive notifications about the progress of the file copy.

My question is whether there should be an anonymous delegate and why (or why not).

Also, does the answer change if:

  • CopyFileEx did not block.
  • If I handed over a delegate that was not anonymous.

Thanks!

+7
source share
3 answers

The delegate should not be pinned. The managed entity is pinned if it cannot be moved by the garbage collector. If the sorting information is correct, the marshalling layer will provide a pointer to something fixed.

However, the above comment, in which you suggest that a local variable can hold a delegate alive, indicates a misunderstanding of the lifetime variable. I refer you to a specification that states:

The actual lifetime of a local variable is implementation dependent. For example, the compiler can statically determine that a local variable in a block is used only for a small part of this block. Using this analysis, the compiler can generate code that causes the variable store to have a shorter lifetime than its containing block. The storage referenced by the local reference variable is restored regardless of the lifetime of this local reference variable

In other words, if you say:

void M() { Foo foo = GetAFoo(); UnmanagedLibrary.DoSomethingToFoo(foo); } 

then the jitter is allowed to say "you know, I see that no managed code ever used foo again after the moment the unmanaged call was called, so I can aggressively return the storage of this object from another thread at that time", This means that the unmanaged call can work above an object when it is suddenly freed from another stream.

This is especially unpleasant if Foo has a destructor. The termination code may run in another thread while the object is being used by an unmanaged library, and heaven only knows that this can lead to disaster.

In this case, you must use KeepAlive to support the managed entity. Do not rely on a local variable; local variables are specifically documented as not , guaranteed to support life.

See http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx for details.

+6
source

You do not need to bind it, but you need to keep a link to it until the copy is executed.

Thunk, caused by unmanaged code, is pinned, but you must make sure that the delegate is not collecting garbage - hence the link.

+3
source

From the following msdn, it seems that both pinning and GC.KeepAlive are not needed in this case, since CopyFileEx is synchronous. In particular, he says:

β€œNormally, you don’t have to worry about delegate lifetimes. Whenever you pass a delegate to unmanaged code, the CLR will make sure that the delegate is alive during the call. However, if the native code contains copy the pointer outside the call range and intend to call back through that pointer later, you may need to use GCHandle to explicitly prevent the garbage collector from collecting a delegate. "

Since CopyFileEx does not store a function pointer outside the call range, we do not need to call KeepAlive.

+2
source

All Articles