调用Invoke挂起程序

时间:2012-12-08 10:19:23

标签: c# multithreading invoke begininvoke

基本上,这就是发生的事情。我有一个线程(无限循环),在表单显示时作为后台进程运行。线程检查是否需要添加新的ToolStripMenuItem。

如果符合条件,我需要使用Invoke才能创建UI对象吗?问题是,当调用this.Invoke或BeginInvoke时,表单变得没有响应,而执行检查的线程仍然正常运行。有什么想法吗?

这是我第一次尝试使用这种多线程游戏。我确定我错过了一些东西。

 public void ThreadSetCom()
    {
        while (true)
        {
            string[] tmpStrPort = System.IO.Ports.SerialPort.GetPortNames();
            IEnumerable<string> diff = tmpStrPort.Except(strPort);
            strPort = tmpStrPort;
            System.Console.WriteLine(System.IO.Ports.SerialPort.GetPortNames().Length);
            foreach (string p in diff)
            {
                var cpDropdown = (ToolStripMenuItem)msMenu.Items["connectToolStripMenuItem"];
                cpDropdown = (ToolStripMenuItem)cpDropdown.DropDownItems["connectReaderToolStripMenuItem"];

                ToolStripMenuItem tsmi = new ToolStripMenuItem();
                tsmi.Text = p;
                tsmi.Name = p;
                tsmi.Click += new EventHandler(itm_Click);

                if (this.msMenu.InvokeRequired)
                {
                    GUIUpdate d = new GUIUpdate(ThreadSetCom);
                    this.Invoke(d);
                }
                else
                {
                    cpDropdownList.DropDownItems.Add(tsmi);
                }                
            }                
        }
    }

3 个答案:

答案 0 :(得分:2)

您的ThreadSetCom方法永不退出:

while (true)

...没有returnbreak语句。这将永远挂起UI线程。

目前尚不清楚你想要实现的目标,但你绝对不希望像在UI线程中那样循环。我认为你不想在任何线程中以的方式循环,请注意......

答案 1 :(得分:0)

我认为更好的方法可能是使用BackgroundWorker。我这样说是因为在Windows窗体应用程序中进行多线程处理时遇到的情况并不少见。此外,BackgroundWorker能够正确地管理线程切换。让我举一个带有BackgroundWorker的代码示例。

构建私有类变量

private BackgroundWorker _worker;

加入CTOR

public {ctor}()
{
    _worker = new BackgroundWorker();
    _worker.WorkerSupportsCancellation = true;
    _worker.WorkerReportsProgress = true;

    _worker.DoWork += new DoWorkEventHandler(BackgroundThreadWork);
    _worker.ProgressChanged += new ProgressChangedEventHandler(BackgroundThreadProgress);
}

DoWork处理程序

private void BackgroundThreadWork(object sender, DoWorkEventArgs e)
{
    while (!_worker.CancellationPending)
    {
        string[] tmpStrPort = System.IO.Ports.SerialPort.GetPortNames();
        IEnumerable<string> diff = tmpStrPort.Except(strPort);
        strPort = tmpStrPort;
        System.Console.WriteLine(System.IO.Ports.SerialPort.GetPortNames().Length);
        foreach (string p in diff)
        {
            _worker.ReportProgress(1, p);
        }                
    }
}

报告进度处理程序

private void BackgroundThreadProgress(object sender, ReportProgressEventArgs e)
{
    var cpDropdown = (ToolStripMenuItem)msMenu.Items["connectToolStripMenuItem"];
    cpDropdown = (ToolStripMenuItem)cpDropdown.DropDownItems["connectReaderToolStripMenuItem"];

    ToolStripMenuItem tsmi = new ToolStripMenuItem();
    tsmi.Text = e.UserState as string;
    tsmi.Name = e.UserState as string;
    tsmi.Click += new EventHandler(itm_Click);

    cpDropdownList.DropDownItems.Add(tsmi);
}

循环

然而,你要做的一件事就是弄清楚如何摆脱这种循环。什么时候应该退出?无论这意味着什么,您需要 添加 到我的示例中存在的 if 语句,因为此循环永远不会以其他方式结束。

答案 2 :(得分:0)

此代码段的效果如何:

GUIUpdate d = new GUIUpdate(ThreadSetCom);
this.Invoke(d);

是将在UI线程中调用'ThreadSetCom'方法。并且该方法中存在不定式循环。这就是为什么你的表单没有反应。

我建议您将foreach子句移动到单独的方法,并在命中条件时在UI线程中调用此方法,例如diff.Count&gt; 0.

相关问题