• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 273
  • Last Modified:

Problem with multithreading

I have a mulitthreaded applicaiton, and I'm having a problem.  When data comes in from the server, it updates some of the controls on a form.  When I then make a call from the GUI thread (button click).  I'm getting an error everytime I hit this line:

foreach(ListViewItem item in contactListView.Items)
                        
that says.  "Error, thread was being stopped".  All the threads that aren't the GUI thread have
t.IsBackground = true;  

I haven't seen this error before and I am never explicitly stopping threads through code.  Any thoughts?
0
jjacksn
Asked:
jjacksn
  • 6
  • 5
1 Solution
 
AlexFMCommented:
Do you update the form directly from worker thread? You should use Invoke or BeginInvoke to do this, these functions serialize calls to the main thread:
http://www.codeproject.com/csharp/workerthread.asp
0
 
jjacksnAuthor Commented:
it is thread safe. (I think).  I'm still having that problem.  Are these symptoms what i would find if it was not thread safe?  I had this multithreaded before and didn't have these problems.  I changed a lot of the code and now it is happening.  
0
 
ptmcompCommented:
You have to synchronize the calls which access the controls of the GUI.
Each control's method starts like:

pulic void AControlMethod(ParamType someParam)
{
    if (Thread.Current != threadCreatedThisControl)
    {
        throw new Exception();
    }
    .... Implemenation of the method....
}

You can only call one method from a foreign thread: Invoke(Delegate, object[])
Where "Delegate" is the delegate to the method you want to invoke (e.g. Show()) and "object[]" is an array of parameters to pass to the method.
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
jjacksnAuthor Commented:
Ok, I have a problem with the Invoking:

I am creating a new instance of the object (the constructor calls InitializeComponents)

When I make a call that then calls invoke:
This method is inside of the form that is getting updated,
ReloadData() gets called from outside of the form.  


public void ReloadData()
{
                  if(this.Loaded)
                  {
                        this.reloadDataOnUnload = true;
                        return;
                  }
                  this.BeginInvoke(m_DelegateReload, null);
            /*      ThreadStart start = new ThreadStart(ReloadDataHelper);
                  Thread t = new Thread(start);
                  t.IsBackground = true;
                  t.Start();*/
            }

The error is that Invoke cannot be called until the main window Handle is created.  However, I am never creating the window handles.  I am pulling the controls out of a panel and loading them into the main window (so I can acheive the same effect as outlook where you click on the button and and then controls in the window change).  Can I not use invoke in this case?  
0
 
ptmcompCommented:
I'm sure Outlook does it differently. You cannot access the controls properties as long they don't exist on a window (= as long they don't have a handle). You can create them invisible and then change the visibility.

From SDK help:
Executes the specified delegate asynchronously with the specified arguments, on the thread that the control's underlying handle was created on.
public virtual IAsyncResult BeginInvoke(Delegate, object[]);
0
 
jjacksnAuthor Commented:
Oh, I'm sure Outlook doesn't it differently as well.  

The basic mechanism I have been using is to create the Forms on a panel, then I switch which panel is loaded in my Main Window.  So I am never actually calling form.Show() or creating the window.  This is working fine, except for what I am talking about.  When I run the method from the GUI thread, it works.  When I run the method by starting a seperate thread when the button is clicked, I have the problem I was talking about.  

If I quickwatch the listViewItem, many of the fields are not populated correctly, but some are.  I'm confused why multithreading would cause these fields not be populated correctly?  (Nothing is happening in my test cases in the main GUI thread when this sepearte thread is running).
0
 
ptmcompCommented:
Try to create the controls, set the owner window but leave them invisible till everything is loaded. You must create the controls in the main thread! That's a restriction of .net framework.
0
 
jjacksnAuthor Commented:
I think what is happening is that I am calling invoke on the class object, which doesn't have a main window.  I think if i call it on the control, I should be fine.  will try tommorrow and let you know.
0
 
jjacksnAuthor Commented:
If I have a long operation (that contacts a server and displays the results in a list view) that I want to run in a seperate thread, do I call BeginInvoke on the whole operation/function as a deleagte?  or do I just create a delegate to wrap around the ListView.Items.Add(listViewItem item)?  and call it in the function that is run in a seperate thread?
0
 
ptmcompCommented:
> I think if i call it on the control, I should be fine.
No, the window must be associated with a windows message queue. I think that's only the case if it has a parent window.
The delegate will run in its own thread so for any manipulation of the GUI you need to call Control.Invoke to synchronize the calls.
0
 
jjacksnAuthor Commented:
So is there no way to accomplish thread safety the way I currently have it structured?  
0
 
ptmcompCommented:
Yes, I think you have to change the structure of your code :o(. (In Win32 your code would probably work but .net has more restrictions.)
0

Featured Post

Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

  • 6
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now