我需要固定匿名代表吗?

发布于 2024-10-26 20:54:09 字数 221 浏览 5 评论 0原文

我从 C# 应用程序调用 CopyFileEx,并将匿名委托传递到 LPPROGRESS_ROUTINE 参数中,以便获取有关文件复制进度的通知。

我的问题是,是否需要固定匿名委托以及为什么(或为什么不)。

此外,如果出现以下情况,答案是否会改变:

  1. CopyFileEx 没有阻塞。
  2. 如果我传入一个非匿名代表。

谢谢!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

离笑几人歌 2024-11-02 20:54:09

委托不需要被固定。如果垃圾收集器无法移动托管对象,则该对象将被固定。如果编组信息正确,则编组层将确保传递指向不可移动对象的指针。

然而,上面的评论表明局部变量可能会使委托保持活动状态,这表明对变量生命周期的误解。我建议您参阅规范,其中规定:

局部变量的实际生命周期取决于实现。例如,编译器可能静态地确定块中的局部变量仅用于该块的一小部分。使用此分析,编译器可以生成导致变量存储的生命周期比其包含块短的代码。
局部引用变量引用的存储空间的回收与该局部引用变量的生命周期无关

换句话说,如果您说:

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

那么允许抖动说“您知道,我看到没有托管代码再次使用 foo调用非托管调用后的那一刻;因此我可以在那时从另一个线程积极地回收该对象的存储”。这意味着当对象突然在另一个线程上释放时,非托管调用可能正在处理该对象。

如果 Foo 有析构函数,这尤其令人讨厌。当非托管库使用该对象时,终结代码可能会在另一个线程上运行,只有天知道这会导致什么样的灾难。

在这种情况下,您需要使用 KeepAlive 来保持托管对象的活动状态。不要依赖局部变量;局部变量被明确记录为不能保证保持活动状态。

请参阅 http://msdn.microsoft.com/en-us/ Library/system.gc.keepalive.aspx 了解更多详细信息。

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.

靑春怀旧 2024-11-02 20:54:09

您不需要固定它,但只要复制正在进行,您就需要保持对它的引用。

非托管代码调用的 thunk 被固定,但您必须确保委托没有被垃圾收集 - 因此是引用。

You don't need to pin it, but you do need to keep a reference to it alive as long as the copy is in progress.

The thunk that is called by the unmanaged code is pinned, but you have to make sure the delegate is not garbage collected - hence the reference.

眼趣 2024-11-02 20:54:09

从以下 msdn 看来固定和 GC.KeepAlive 都是在这种情况下不需要,因为 CopyFileEx 是同步的。具体来说,它说:

“通常,您不必担心委托的生命周期。每当您将委托传递给非托管代码时,CLR 都会确保该委托在调用期间处于活动状态。但是,如果本机代码保留超出调用范围的指针副本并打算稍后通过该指针回调,您可能需要使用 GCHandle 来显式阻止垃圾收集器收集委托。”

由于 CopyFileEx 不会在调用范围之外保留指向函数的指针,因此我们不需要调用 KeepAlive。

From the following msdn seems like both pinning and GC.KeepAlive are unneeded in this case since CopyFileEx is synchronous. Specifically it says:

"Usually, you won't have to worry about the lifetime of delegates. Whenever you are passing a delegate to unmanaged code, the CLR will make sure the delegate is alive during the call. However, if the native code keeps a copy of the pointer beyond the span of the call and intends to call back through that pointer later, you might need to use GCHandle to explicitly prevent the garbage collector from collecting the delegate."

Since CopyFileEx does not keep a pointer to the function beyond the span of the call, we shouldn't need to call KeepAlive.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文