Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
601 views
in Technique[技术] by (71.8m points)

c# - Do I need to pin an anonymous delegate?

I am calling CopyFileEx from a C# application with an anonymous delegate being passed into the LPPROGRESS_ROUTINE parameter in order to get notifications on the file copy progress.

My question is, does the anonymous delegate need to be pinned and why (or why not).

In addition, does the answer change if:

  1. CopyFileEx was not blocking.
  2. If I passed in a delegate that was not anonymous.

Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The delegate does not need to be pinned. A managed object is pinned if it cannot be moved by the garbage collector. If the marshalling information is correct then the marshalling layer will ensure that a pointer to something immobile is passed.

However, the comment above where you suggest that a local variable might keep the delegate alive indicates a misunderstanding of variable lifetime. I refer you to the spec, which states:

The actual lifetime of a local variable is implementation-dependent. For example, a compiler might statically determine that a local variable in a block is only used for a small portion of that block. Using this analysis, the compiler could generate code that results in the variable’s storage having a shorter lifetime than its containing block. The storage referred to by a local reference variable is reclaimed independently of the lifetime of that 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 uses foo again the moment after the unmanaged call is invoked; I can therefore aggressively reclaim the storage of that object from another thread at that time". Which means that the unmanaged call can be working on the object when suddenly it is deallocated on another thread.

This is particularly nasty if Foo has a destructor. The finalization code will possibly run on another thread while the object is in use by the unmanaged library, and heaven only knows what sort of disaster that will cause.

In this circumstance you are required to use a KeepAlive to keep the managed object alive. Do not rely on a local variable; local variables are specifically documented as not guaranteed to keep things alive.

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...