Windows 窗体:有没有办法等待对控件的所有挂起调用结束?
我需要这样做才能解决僵局。 我的 Windows 窗体控件引用了包装 C++ 本机类的 C++/CLI 类。本机类对 C++/CLI 类进行回调,后者将它们映射到表单处理的事件。这些回调是从始终运行的线程中调用的。
当我想要处置该控件时,我取消注册所有事件,以便本机类无法再回调。完成后,我将处理 C++/CLI 包装器,这又会破坏本机类。在本机类析构函数中,我使用 Windows 事件向线程发出结束信号,并无限期地等待线程结束。
但是,如果处理开始时线程正处于回调过程中,则他可能会在 Control.Invoke
中停止,并随之发生死锁。因此标题问题。这可能吗?如果是这样,我可以这样继续:
- 取消注册所有事件(本机线程将无法再回调)
- 等待所有挂起的 .Invokes 完成
- 处理 C++/CLI 包装器
- 销毁 C++ 原生类
- 指示线程结束
- 等待线程结束(不能与
Invoke
发生死锁,因为所有这些都已完成,而且由于事件未注册,因此无法再触发任何线程)
- 销毁 C++ 原生类
- Bliss
I'我愿意接受解决此问题的其他建议
I need to do this in order to solve a deadlock.
My Windows Forms Control has a reference to a C++/CLI class which wraps a C++ native class. The native class makes callbacks to the C++/CLI class, which maps them to events handled by the form. These callbacks are called from a thread which runs all the time.
When I want to dispose the control, I unregister all events, so that the native class can't call back anymore. Once that's done, I dispose the C++/CLI wrapper, which in turn destroys the native class. In the native class destructor, I signal the thread to end using a Windows event, and wait indefinitely for the thread to end.
However, if the thread was in the middle of a callback when the disposal starts, he might be stopped in a Control.Invoke
, and deadlock ensues. Hence the title question. Is this possible? If it were so, I could proceed this way:
- Unregister all events (native thread won't be able to call back anymore)
- Wait for all pending .Invokes to finish
- Dispose C++/CLI wrapper
- Destroy C++ native class
- Signal thread to end
- Wait for thread to end (can't deadlock with an
Invoke
since all of those finished and no more of them could have been fired since events were unregistered)
- Destroy C++ native class
- Bliss
I'm open to other suggestions for solving this problem
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
选项 1:通过 Application.DoEvents< 处理挂起的回调/a> 在删除事件处理程序之后但在析构函数之前。请注意,文档说这会处理 Windows 消息,但没有提及这是否会强制处理调用。
选项 2:不阻塞事件线程:通过 BeginInvoke 调用表单回调。请注意,您可能会在 C++ 对象被销毁后收到事件,因此向事件处理程序添加额外的逻辑以确保 C++ 对象未被销毁。
仅供参考,
BeginInvoke
和Invoke
都使用此函数。BeginInvoke
将synchronous
设置为 false。请注意,我对此方法进行了一些修改,以删除无趣的部分:Option 1: Process pending callbacks via Application.DoEvents after removing the event handlers but before the destructor. Note the documentation says this handles Windows messages and does not mention if this forces processing of Invokes.
Option 2: Do not block the event thread: Call your form callbacks via BeginInvoke. Note that you might get events after the C++ object is destroyed, so add additional logic to the event handlers to ensure the C++ object has not been destroyed.
FYI,
BeginInvoke
andInvoke
both use this function.BeginInvoke
setssynchronous
to false. Note that I hacked this method up a bit to remove the uninteresting portions:不可能响应表单关闭事件并等待线程完成。存在无法解决的线程竞争条件。 DoEvents 很可能会打破僵局,但它太丑陋了。
实现 FormClosing 事件并告诉类停止运行其线程。并取消关闭。线程应该在退出之前引发一个事件。在事件处理程序中使用 BeginInvoke() 将该调用编组到主线程。
现在您可以保证所有调用都已完成,因为它们已排序。此外,您还可以保证线程不再生成任何更多事件,因此不会再有任何调用,并且可以安全地取消订阅事件(实际上没有必要)。设置一个标志,表明现在可以真正关闭,并调用 Close() 来实际关闭表单。
There is no possibility of responding to the form closing event and wait for the thread to finish. There's an unsolvable threading race condition. And very good odds for deadlock, DoEvents would break it but is too ugly.
Implement the FormClosing event and tell the class to stop running its thread. And cancel the close. The thread should raise an event just before it exits. Use BeginInvoke() in the event handler to marshal that call to the main thread.
Now you have a guarantee that all invokes are completed since they are ordered. Furthermore, you have a guarantee that the thread can no longer generate any more events so no more invokes are coming and it is safe to unsubscribe the events (not actually necessary). Set a flag that a real close is now possible and call Close() to actually close the form.