关于 Invoke、Invokerequired 和多线程的 C# 问题

Posted

技术标签:

【中文标题】关于 Invoke、Invokerequired 和多线程的 C# 问题【英文标题】:C# Questions regarding Invoke, Invokerequired & Multithreading 【发布时间】:2016-09-11 02:55:46 【问题描述】:

我有 2 个表单在不同的线程上运行。 Form2 将生成一个字符串,将其发送回 form1 并更新 form1 中的富文本框。我从朋友那里得到了代码,但我不明白其中的一部分。

你能解释一下为什么我们需要这个条件吗:

if (this.f1_rtb_01.InvokeRequired)  

下面两行是做什么的?

SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[]  text );

完整代码表格1:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace PassingData2Forms

public partial class Form1 : Form

    public Form1()
    
        InitializeComponent();
    

    public string str_1;

    private void call_form_2()
    
        for (int i = 0; i < 10; i++)
        
            Form2 inst_form2 = new Form2();
            inst_form2.ShowDialog();

            string result = inst_form2.SelectedString;
            this.SetText(result);
        
    

    delegate void SetTextCallback(string text);

    private void SetText(string text)
    
        if (this.f1_rtb_01.InvokeRequired)
        
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[]  text );
        
        else
        
            if (text != "")
            
                this.f1_rtb_01.AppendText(text + Environment.NewLine);
            
            else
            
                this.f1_rtb_01.AppendText("N/A" + Environment.NewLine);
            
        
    

    private void f1_but_01_Click(object sender, EventArgs e)
    
        Thread extra_thread_01 = new Thread(() => call_form_2());
        extra_thread_01.Start();            
    


【问题讨论】:

为什么要在两个线程上运行两个表单? 【参考方案1】:

这部分:

SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[]  text );

使当前表单调用SetTextCallback 委托的实例,将变量text 作为参数传递。委托实例指向SetText() 方法,由于调用this.Invoke(),该方法将在与表单相同的线程上执行。

调用用于将代码的执行从后台线程移动到窗体/控件的线程,从而使执行线程安全。

这部分只是为了检查你是否需要调用:

if (this.f1_rtb_01.InvokeRequired)

如果您不需要调用,则表示代码已经在窗体或控件的线程上运行,如果您尝试调用,将引发异常。

【讨论】:

【参考方案2】:

每个表单在不同的线程上运行。让我们称它们为 thread1 和 thread2。由于您想从 thread1 更新 thread2 上的某些内容,因此您需要让这两个线程相互通信。这就是invoke 的工作

条件是检查是否需要调用。如果您在 thread1 本身上更新 thread1 中的字符串,则不需要调用,否则它是。

【讨论】:

以上是关于关于 Invoke、Invokerequired 和多线程的 C# 问题的主要内容,如果未能解决你的问题,请参考以下文章

invokeRequired属性和 invoke()方法[转载的]

InvokeRequired

invokeBeanFactoryPostProcessors详解

多线程UI

非法交叉线程操作异常的任何解决方案?

调用(委托)