2

在异步 OnMsgRecieved 调用中,如果我将值直接分配给控件,则它不起作用。然后我才知道这是由于线程不安全,我得到了以下代码来解决这个问题。现在它正在工作。但我不确定它实际上做了什么。任何人都可以让我完全理解它吗?代码是: -

        public void listener_OnMsgRecieved(string aResponse)
    {
        ShowResponseMessage(aResponse);
    }

    public void ShowResponseMessage(string aResponse)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.listBox.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(ShowResponseMessage);
            this.Invoke(d, new object[] { aResponse });
        }
        else
        {
            this.listBox.Items.Add(aResponse);
            label.Text = "Response received from Server :";
        }
    }
4

2 回答 2

1

当在与 UI 不同的线程上调用 ShowResponseMessage 时,InvokeRequired将返回true,然后您正在使用Control.Invoke将消息发送到 Windows 消息队列。

在 UI 线程中运行的 UI 消息泵将拉取消息并将其传递给目标控件,然后目标控件会看到这是一条请求调用委托的消息,并且委托由控件调用,现在是在 UI 线程上运行,因此跨线程问题已得到解决。

诀窍是委托不是直接在非 UI 调用线程上调用的。使用 Windows 消息将执行委托的指令传递给 UI 线程,然后 UI 线程执行委托以响应消息。'Control.Invoke' 使用 Windows [SendMessage][1]Control.BeginInvoke使用[PostMessage][2]Win32 API 来促进消息传递。

于 2012-04-24T05:26:21.987 回答
0

UI 控件不能从创建它的主线程/线程以外的任何线程更新/更改。

在您的情况下,检查 InvokeRequired 会检查希望更改控件的线程是否是创建线程,如果不是,则将调用传递回主线程/创建者。

查看如何:对 Windows 窗体控件进行线程安全调用

如果使用多线程来提高 Windows 窗体应用程序的性能,则必须确保以线程安全的方式调用控件。

对 Windows 窗体控件的访问本质上不是线程安全的。如果您有两个或更多线程操作控件的状态,则可能会强制控件进入不一致的状态。其他与线程相关的错误是可能的,例如竞争条件和死锁。确保以线程安全的方式执行对控件的访问非常重要。

在不使用 Invoke 方法的情况下从创建控件的线程以外的线程调用控件是不安全的。

于 2012-04-24T05:25:47.590 回答