简体   繁体   English

C#:如何通过从另一个线程以某种方式发出信号来强制从主线程“调用”一个方法

[英]C#: How to force "calling" a method from the main thread by signaling in some way from another thread

Sorry for long title, I don't know even the way on how to express the question对不起,标题太长,我什至不知道如何表达问题

I'm using a library which run a callback from a different context from the main thread (is a C Library), I created the callback in C# and when gets called I would like to just raise an event.我正在使用一个库,它从主线程的不同上下文(是一个 C 库)运行回调,我在 C# 中创建了回调,当被调用时,我只想引发一个事件。

However because I don't know what will be inside the event, I would like to find a way to invoke the method without the problem of locks and so on (otherwise the third party user will have to handle this inside the event, very ugly)但是因为不知道事件里面会发生什么,所以想找到一种方法来调用方法,没有锁等问题(否则第三方用户就得在事件内部处理这个,非常丑陋)

Are there any way to do this?有没有办法做到这一点? I can be totally on the wrong way but I'm thinking about winforms way to handle different threads (the .Invoke thing)我可能完全走错了路,但我正在考虑用 winforms 的方式来处理不同的线程(.Invoke 的事情)

Otherwise I can send a message to the message loop of the window, but I don't know a lot about message passing and if I can send "custom" messages like this否则我可以向窗口的消息循环发送消息,但我对消息传递知之甚少,以及我是否可以发送这样的“自定义”消息

Example:例子:

private uint lgLcdOnConfigureCB(int connection, System.IntPtr pContext)
{
    OnConfigure(EventArgs.Empty);
    return 0U;
}

this callback is called from another program which I don't have control over, I would like to run OnConfigure method in the main thread (the one that handles my winform), how to do it?这个回调是从另一个我无法控制的程序调用的,我想在主线程(处理我的 winform 的线程)中运行 OnConfigure 方法,该怎么做? Or in other words, I would like to run OnConfigure without the need of thinking about locks或者换句话说,我想在不需要考虑锁的情况下运行 OnConfigure

Edit 1:编辑1:

I have a problem with this exception:我有这个例外的问题:

CallbackOnCollectedDelegate retrived Message: Callback run on delegate 'G19dotNet!G19dotNet.LgLcd+lgLcdOnSoftButtonsCB::Invoke' collected in GarbageCollector. CallbackOnCollectedDelegate 检索到的消息:在 GarbageCollector 中收集的委托“G19dotNet!G19dotNet.LgLcd+lgLcdOnSoftButtonsCB::Invoke”上运行的回调。 During unmanaged code delegates should be ensured will never be deleted until you are sure they will never be called在非托管代码委托期间应确保永远不会被删除,直到您确定它们永远不会被调用

Edit 2:编辑2:

Issue resolved by myself, thanks to Stackoverflow which always helps me!问题由我自己解决,感谢 Stackoverflow 总是帮助我! For future reference: Defining a delegate as a function pointer供将来参考: 将委托定义为函数指针

If you're using WinForms and you want to execute something on the UI thread, you need to call either Invoke or BeginInvoke on some control (be it a Button or a Form or whatever) that was created on that thread. 如果您正在使用WinForms并且想要在UI线程上执行某些操作,则需要在该线程上创建的某些控件(无论是Button还是Form或其他)上InvokeBeginInvoke You'll need a reference to it in order to do this. 为了做到这一点,你需要一个引用它。

For example, with your code and assuming that you have a reference to a form called form : 例如,使用您的代码并假设您有一个名为form的表单的引用:

private uint lgLcdOnConfigureCB(int connection, System.IntPtr pContext)
{
    form.Invoke(new MethodInvoker(() => OnConfigure(EventArgs.Empty)));
    return 0U;
}

Before you call the 3rd party function, get a reference to Dispatcher.CurrentDispatcher. 在调用第三方函数之前,请获取对Dispatcher.CurrentDispatcher的引用。 In the callback function, use dispatcher.Invoke. 在回调函数中,使用dispatcher.Invoke。

What you end up with will look something like this: 你最终得到的将是这样的:

class MyClass
{
    private Dispatcher dispatcher;
    public void runThirdParty()
    {
        this.dispatcher = Dispatcher.CurrentDispatcher;
        callThirdPartyFunction(myCallBack);
    }

    public void myCallBack()
    {
        this.dispatcher.Invoke(new Action(() =>
        {
            //code to run here.
        }));
    }
 }

There is a pattern for this called Event-based Asynchronous Pattern . 这种称为基于事件的异步模式有一种模式 The article linked is a great overview on how to use it. 链接的文章是关于如何使用它的一个很好的概述。 The AsyncOperation class is the key to this pattern. AsyncOperation类是此模式的关键。

This pattern might not fit perfectly with your problem that you are trying to solve, but it might give you some insights into the problem. 这种模式可能不完全适合您尝试解决的问题,但它可能会让您对问题有所了解。

Thanks to Adam Robinson answer , I added a nice little utility function on my form:感谢 Adam Robinson 的回答,我在表单上添加了一个不错的小实用函数:

   private void runOnUIThread(Action function)
   {
       this.Invoke(new MethodInvoker(function));
   }

And I'm using it like this:我是这样使用它的:

   runOnUIThread(() =>
   {
       example_lbl_status.Text = "Active";
   });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM