Question

Basically, this is what happens. I have a thread(endless loop) that runs as a background process while the form is showing. The thread checks if there is a need to add a new ToolStripMenuItem.

If the conditions are met, I'll need to use Invoke in order to create the UI object right? Problem with this is, when the this.Invoke or BeginInvoke is called, the form became unresponsive while the thread that does the checking is still running fine. Any ideas?

This is the first time i'm trying with this multithreading thingee. I'm sure i've missed out something.

 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);
                }                
            }                
        }
    }
Was it helpful?

Solution

Your ThreadSetCom method never exits:

while (true)

... with no return or break statements. That's going to hang the UI thread forever.

It's not clear what you're trying to achieve, but you definitely don't want to be looping like that in the UI thread. I'd argue that you don't want to be looping like that in a tight way in any thread, mind you...

OTHER TIPS

I think a better approach for you would probably be to use a BackgroundWorker. I say that because what you're experiencing isn't that uncommon when doing multi-threading in a Windows Forms application. Further, the BackgroundWorker is able to manage the thread switching properly. Let me give you an example of that code with the BackgroundWorker.

Build a private class variable

private BackgroundWorker _worker;

Add to the CTOR

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

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

DoWork handler

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);
        }                
    }
}

Report progress handler

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);
}

The Loop

However, one thing you're going to have to do is figure out how to get out of this loop. When should it exit? Whatever that means, you need to add to the if statement that exists there in my example because this loop will never end otherwise.

What the effect of this code snippet:

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

is that the method 'ThreadSetCom' will be invoked in the UI thread. And there is an infinitive loop in that method. That is why your form becomes unresponsive.

I suggest you that you should move the foreach clause to a separate method and invoke this method in the UI thread when the condition is hit, for example the diff.Count>0.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top