views:

524

answers:

4

Hello all,

I am trying to build a small application that logins into a server and gathers data from it constantly. The problem that I am having is that my GUI is slow to respond even when using either background worker or a thread. When my application tries to login into the server, I see "(Not Responding)" appear in my login form, but it logins in few seconds later without Windows giving the "The program has stopped responding... terminate application" dialog. When I click the start button on my application I noticed by GUI becomes very sluggish and unresponsive. I was wondering how I could improve the response time of my program. Here is the code for the Login form using a background worker and the code for my thread that gathers data from the server. I apologize for the last section of the code not being format correctly, but SO is being non-cooperative.

    private void btnLogin_Click(object sender, EventArgs e)
    {
        if (string.IsNullOrEmpty(txtAccount.Text) || string.IsNullOrEmpty(txtPassword.Text))
        {
            MessageBox.Show("Must Enter Username and Password");
            return;
        }
        btnLogin.Enabled = false;
        account = txtAccount.Text;
        password = txtPassword.Text;
        accountType = cmbAccountType.SelectedItem.ToString();
        loginBackgroundWorker.RunWorkerAsync();
    }

    private void loginBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        loginSuccess=tradingDesk.Login(account, password, accountType);
    }

    private void loginBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (loginSuccess)
        {
            this.DialogResult = DialogResult.OK;
        }
        btnLogin.Enabled = true;
    }


    private void btnStart_Click(object sender, EventArgs e)
        {
        Thread dataThread=new Thread(GetServerData);
        dataThread.IsBackground=true;

        try
        {
            dataThread.Start();
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.Message);
        }}

private void GetServerData()
{
    try
    {
        while (true)
        {
            lock (myLock)
            {
               //Perform Server Task with large amounts of data
            }
        }
    }
    catch
    {
        //Handle exception code
    }
}
A: 

Try setting Thread.Priority to something lower than the GUI.

Also, your thread is on the same cpu/core as the app (same process) so if it uses 100% then even with a lowered priority you might notice a difference.

There is a library I can't recall off the top of my head for parallel processing across cpus/cores - try that if priority doesn't fix it

Luke Schafer
+1  A: 

Try using BackgroundWorker for your processing - easier than handling threads yourself unless you're in the business of handling threads in a pool and you like that stuff (or you've been doing it like that since v1.0 as I have - you're just used to it that way).

I also put all my UI interactions into a background thread and marshall the calls back through to the UI thread. This article should help you out on both: Tools for Updating Windows Forms UI from Background Threads

Another test is to swap out your call to tradingDesk.Login with a simple sleep to see if that changes anything. And how's your CPU? Happen to notice if the thread or process spikes in CPU usage? Even a multi-threaded app that eats up all your CPU will stutter - Flash comes to mind - slows down my entire system even other processes.

databyte
Hello Databyte,Thank you for your reply. I am not making any updates to my GUI through the tread or background worker. I replaced my tradingDesk.Login with a 30 second sleep and the GUI works as expected. When I run the background worker with the tradingDesk I notice the my CPU jumps up about 2%, but it is still under 20%.
Dylan
What type of object is tradingDesk and does it have any legacy or non-thread-safe problems?
databyte
Thanks for the reply Databyte. I found that tradingDesk contained a COM object that was causing the main thread to wait.
Dylan
A: 

This seems strange to me...:

private void btnStart_Click(object sender, EventArgs e)
{
    Thread dataThread = new Thread(GetServerData);  // Won't this go out of scope?
    dataThread.IsBackground = true;

    try
    {
        dataThread.Start();     // Isn't this asynchronous (i.e. doesn't block)?
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Seems to me that either dataThread.Start() is a blocking call, thus causing your UI thread to stall, or it's a non-blocking call, in which case the local reference dataThread goes out of scope almost immediately (presumably before the thread has had time to finish it's work)?

Scott Smith
Hello Scott,The dataThread is actually in the the class and not in the method. I accidentally put it in the method when the trying to format the code correctly. Good observation.
Dylan
A: 

This is a perfect example of why ThreadPool exists. Please note, when you pass the delegate to the method you want threaded to the ThreadPool, the main UI thread (the one that drives the message pump) is free and clear, waiting for the next UI event. Unless you are communicating frequently with the UI thread, there should be no reason that the UI thread is bogged down to the point of becoming unresponsive.

private void btnStart_Click(object sender, EventArgs e)
{
   // spawn the GetServerData() method on the ThreadPool
   ThreadPool.QueueUserWorkItem(new WaitCallback(GetServerData));

   // after the above is called, you'll immediately get here because
   // the UI thread is free from having to process GetServerData()
   return;
}

Note: WaitCallback delegate requires a single parameter of an object. Also, note the comment on the "lock" statement below.

private void GetServerData(object o)
{
   try
   {
      while (true)
      {
         // if ANYTHING in the UI thread requires this lock (recurring timer),
         // you've just eliminated ANY benefit to having this on a separate thread
         lock (myLock)
         {
            // processor intensive code
         }
      }
   }

   catch
   {
      // handle exceptions
   }
}
Michael