2

基本的に、これが起こることです。フォームが表示されている間にバックグラウンド プロセスとして実行されるスレッド (無限ループ) があります。スレッドは、新しい ToolStripMenuItem を追加する必要があるかどうかを確認します。

条件が満たされた場合、UI オブジェクトを作成するために Invoke を使用する必要がありますよね? これに関する問題は、 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);
                }                
            }                
        }
    }
4

3 に答える 3

2

あなたのThreadSetComメソッドは決して終了しません:

while (true)

... returnorbreakステートメントなし。これにより、UI スレッドが永久にハングアップします。

何を達成しようとしているのかは明確ではありませんが、UI スレッドでそのようにループしたくないことは間違いありません。どのスレッドでも、そのようにタイトにループしたくないと思いますが、気をつけてください...

于 2012-12-08T10:51:55.043 に答える
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);
}

ループ

ただし、実行する必要があることの1つは、このループから抜け出す方法を理解することです。いつ終了する必要がありますか?それが何を意味するにせよ、このループは他の方法で終了することはないので、私の例に存在するifステートメントに追加する必要があります。

于 2012-12-08T11:04:24.633 に答える
0

このコード スニペットの効果:

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

メソッド 'ThreadSetCom' が UI スレッドで呼び出されることです。そして、そのメソッドには無限ループがあります。そのため、フォームが応答しなくなります。

foreachこの句を別のメソッドに移動し、diff.Count>0 などの条件に一致したときに UI スレッドでこのメソッドを呼び出すことをお勧めします。

于 2012-12-08T11:12:03.887 に答える