?
Solved

Error: Cross-thread operation not valid - Using Multi-Threading

Posted on 2007-08-02
22
Medium Priority
?
578 Views
Last Modified: 2011-09-20
I am trying to add an item to a listbox. The lst.Items.Add is being performed within a custom event on the form. I am getting the error:
  Cross-thread operation not valid: Control 'lstProcessed' accessed from a thread other than the thread it was created on.

I am probably about the densest person around when it comes to understanding multithreading. However, there is reference in the error and MS help about using CheckForIllegalCrossThreadCalls. When I add it I get the warning:
  Access of shared member, constant member, enum member or nested type through an instance; qualifying expression will not be evaluated.
but it seems to work.

My questions: what are the ramifications of using this property? Will the warning lead to any serious consequenses down the road? Where can I find information that can be rather easily digested (I am cramming TOO much into my head right now to try to absorb anything too deep) on using multi-threading?

This is my 3rd question relating to one project I am working on. I have a feeling it probably should be multi-threaded but have no idea how to do it.

I have a form that is creating multiple instances of a class that can raise events back to the form. Each class has different values set on properties that basically set up a FileSystemWatcher. I watch several different directories and different filters on each one. When the FSW files in the class, it processes the file, then raises an event back to the form that basically just adds an item to a listbox giving the path, filename and status of the processed file. The class then goes back to watching the directory.

0
Comment
Question by:dbbishop
22 Comments
 
LVL 96

Expert Comment

by:Bob Learned
ID: 19620707
Control.CheckForIllegalCrossThreadCalls = False

bob
0
 
LVL 18

Expert Comment

by:Priest04
ID: 19620910
The exception that you have been receiving is a debug-error, it will not raise when you compile. To remove this exception, you can use suggestion by Bob, but as I read some discussion about this topic, advises from some MS guys were not to use this approach, but

private sub MyFunction()

if (this.InvokeRequired)
{
    this.Invoke(new MethodInvoker(MyFunction));
}
else
{
    // use control here
    lst.Items.Add("some item")
}

Goran
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19621491
Bob,

Because of the error I added lstProcessed.CheckForIllegalCrossThreadCalls = False
That gave me the warning.

Goran,

Would I use the code you provided along with using the CheckForIllegalCrossThreadCalls property?
Does this.Invoke(new MethodInvoker(MyFunction)) reinvoke the method? If not, I can't see how the item would get added to the list.

Again, what are the ramifications to doing this? What are the chances that doing this would crash the program? According to the documentation, using CheckForIllegalCrossThreadCalls sets the behavior to that of VB 2003.

To reiterate the other part of this question:  Where can I find information that can be rather easily digested (I am cramming TOO much into my head right now to try to absorb anything too deep) on using multi-threading?

I would like something along the lines of "Thread Pooling for Dummies," something that will explain it step-by-step, like, "This is a thread..."

Sorry for being so persistent, but I am relatively new to .net and totally new (as of today) to the nuances of multi-threading.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 18

Expert Comment

by:Priest04
ID: 19621661
I am using the code I have posted for quite a long time and I had no problems with it. And no, it doesn't involve CheckForIllegalCrossThreadCalls to be set.

You can use google to learn more about threading, there are many sites that deal with it. I will try to explain in my words what is this code doing.

Controls belong to a specific thread and are not thread safe. So, when you want to use control from another thread (like calling some control's method), you need to use Invoke method, which marshals this call to appropriate thread that control belongs to. But before you do this, you check with InvokeRequired if Invoke is needed. Invoke required will return false in two situations: if controls belongs to this thread, or if control's handle is not yet created. If InvokeRequired returns true, then using Invoke method call is passed to control's thread, and this thread will call MyFunction method safely. To learn more about InvokeRequired, and Invoke, you can read about it from MSDN.

Goran
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19621740
I'll give it a try tomorrow. Thanks.
0
 
LVL 18

Expert Comment

by:Priest04
ID: 19621835
Maybe this article is good to read

http://weblogs.asp.net/justin_rogers/articles/126345.aspx

Goran
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19624759
Priest04, Having a bit of trouble (VB). I coded the following:

    Public Sub OnNewFileProcessedEvent(ByVal source As Object, ByVal e As FileProcessedEventArgs)

        If (Me.InvokeRequired) Then
            Me.Invoke(New MethodInvoker(OnNewFileProcessedEvent))
        Else
            lvwProcessed.Items.Add("some item")
        End If

That gives the error: "'System.Windows.Forms.MethodInvoker' is a delegate type and requires a single 'addressof' expression as the only argument to the constructor."

So I changed the Invoke to:
    Me.Invoke(New MethodInvoker(AddressOf OnNewFileProcessedEvent))

and got the error:
"Method 'Public Sub OnNewFileProcessedEvent(source As Object, e As FileRecordCounts.FileProcessedEventArgs)' does not have the same signature as delegate 'Delegate Sub MethodInvoker()'."

So I changed it to:
    Me.Invoke(New MethodInvoker(AddressOf OnNewFileProcessedEvent(ByVal source As Object, ByVal e As FileProcessedEventArgs)))

And got the error: "Expression Required" referring to the two ByVal statements, leaving:
    Me.Invoke(New MethodInvoker(AddressOf OnNewFileProcessedEvent(source As Object, e As FileProcessedEventArgs)))

So I removed the ByVal's and got:
  "'AddressOf' operand must be the name of a method (without parentheses)." along with "Comma, ')', or a valid expression continuation expected." referencing the 'As' keywords.

I AM SOOOO LOST!!!!
0
 
LVL 18

Expert Comment

by:Priest04
ID: 19625893
Since you are reinvoking an event, you should pass as first parameter delegate, and as 2nd parameter arguments. I dont know what is the name of your declared delegate, but if it is FileProcessedEventhandler then it should be

Public Sub OnNewFileProcessedEvent(ByVal source As Object, ByVal e As FileProcessedEventArgs)

If (Me.InvokeRequired) Then
    Me.Invoke(New FileProcessedEventHandler(Addressof OnNewFileProcessedEvent), new object() {source, e})
Else
    Me.lvwProcessed.Items.Add("some item")
End If

I will give you an example of how it is done with BackGroundWorker component, it runs in different thread, and event is reinvoked, as in your case

    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        If Me.InvokeRequired Then
            Me.Invoke(New DoWorkEventHandler(AddressOf BackgroundWorker1_DoWork), New Object() {sender, e})
        Else
            Me.Button1.Text = "Started"
        End If

    End Sub

Goran
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19627860
Goran,
Again, I am going to show my ignorance. I am not sure I understand what you mean.
My form creates the handler for the event in the following manner for each instance of cImportFile I create (cJobClass is the instance of cImportFile):

    AddHandler cJobClass.NewFileProcessedEvent, AddressOf Me.OnNewFileProcessedEvent
    AddFile(cJobClass)

This is done for each node in the XML file.

In cImportFile I have the following declaration:
    Public Event NewFileProcessedEvent(ByVal sender As Object, ByVal e As FileProcessedEventArgs)

Then I raise the event in cImportFile with:
    RaiseEvent NewFileProcessedEvent(Me, New FileProcessedEventArgs(mstrSourceFilePath, e.Name, mlngImportStatus, dtProcessDate))

In the form, I capture the event with:
    Public Sub OnNewFileProcessedEvent(ByVal source As Object, ByVal e As FileProcessedEventArgs)

All I want to do in OnNewFileProcessedEvent() is read properties in e and add them to a listview.
0
 
LVL 18

Accepted Solution

by:
Priest04 earned 2000 total points
ID: 19628216
:) Ok, so you don't have a delegate, no big deal, we will create one. We need delegate so we can invoke method with parameters

In your class cImportFile add this delegate

Public Delegate Sub NewFileProcessedEventHandler(ByVal sender As Object, ByVal e As FileProcessedEventArgs)

and change your event declaration from

Public Event NewFileProcessedEvent(ByVal sender As Object, ByVal e As FileProcessedEventArgs)

to this

Public Event NewFileProcessedEvent As NewFileProcessedEvent

and finally, the line that gave you headaches

Me.Invoke(New cImportFile.NewFileProcessedEventHandler(Addressof OnNewFileProcessedEvent), new object() {source, e})

Will this wok?

Goran
0
 
LVL 19

Expert Comment

by:weellio
ID: 19633184
http://www.15seconds.com/issue/020815.htm

additional delegate information
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19658611
Goran,
Sorry I have not gotten back to you. I got put back into some other development and had to leave this hanging for a few days, which is bad because I need to keep using it or I'll forget it all :-)

I am still a little uncertain of how to set this up so it notifies me when the file has finished being copied? To tell you the truth, I moved from VB 6/SQL Server development on my previous job to doing some ASP/VB.NET stuff back in April (first exposure to either). Then I changed jobs in June and went into SQL Server development, and had this particualr project dumped on me early last week. The SQL stuff I am working on is existing code that is VERY esoteric and hard to follow. That combined with learning new technologies is really taxing my brain cells right now.

I've done SOME coding in VB6 using events (other than those that come standard with your controls) so I have a little understanding of it, in that PRIVATE WITHEVENTS clsMyClass as aClass is pretty much the same as using ADDHANDLER in .NET, but beyond that I am still lost. Sorry for being so dense!

We seem to have digresed from the original topic (adding an item to a listbox) and I still have not gotten anything to work using the Invoke methods (which seem to be a little cleaner than using CheckForIllegalCrossThreadCalls) and I would be happy to close this question and start a new one if you'd prefer, but I would really appreciate some help getting through all this.
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19658617
Actually, if you want to answer this in question http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_22740715.html that might give me a better way of properly assigning points.
0
 
LVL 18

Expert Comment

by:Priest04
ID: 19659055
Considering the invoking method on the correct thread question, I believe that you should not have any problems with implementing this solution, just follow the posts. Mostly all of the people from VB.NET also worked with VB6, myself too. The transition is not hard, you just need to understand how OOP works. VB6 got us a little of the road, since it wasnt OOP languge completely. When I started VB.NET, I had problems with accesing forms, and it was so easy in VB6. They even implemented those public variables (VB6 style) that hold reference to forms in VB.NET 2005, which I find high;y unnecessary, and a step behind.

As fpr the above link, I cant give you any better advice that Idle_Mind has, so there is no point to just confirm what Idle_Mind said. If you don't know how to implement it, just post, I am sure that Idle_Mind will help you, since it takes only a few lines of code to achieve what you want.

Goran
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19659433
Goran,

Thanks for the vote of confidence. I know just need to take the time to absorb it all. Part of me wishes I could be eiter full time SQL Server or .net, one or the other. Bouncing back and forth is kind of dizzying. However, another part of me appreciates the challenge of learning new stuff. I've come a long way from the days of DOS-based GW BASIC and FORTRAN.

I still need some info on exactly how to how to set things up so I can get an event when a file finishes copying to a directory.
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19659442
I guess what I am referring to is your post above stating:
:) Ok, so you don't have a delegate, no big deal, we will create one. We need delegate so we can invoke method with parameters.

You seem to indicate there is a 'better' way to do it than what Idle_Mind suggested, in steeting a timer and rechecking, which, by the way, is what I had already done. But since I am still not sure how to instantiate each of these classes into separate threads, a timer invoked in oe of the classes freezs the entire application. I am reading up some on thread pooling. Just need to get a better handle on it.
0
 
LVL 18

Expert Comment

by:Priest04
ID: 19664204
>> :) Ok, so you don't have a delegate, no big deal, we will create one. We need delegate so we can invoke method with parameters.

I was never referring to anything correlated to timer, filesystemobject, or monitoring some file to see when it was created. Your question was how to access a listbox from another thread, and all my posts were related to this question. Since your event NewFileProcessedEvent has custom parameters, you must create a delegate with identical signature in order to raise this event using Invoke.

Goran
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19692857
Goran,
Going back to your answer ID:19628216 on 08.03.2007:
I understand the changes to be made in cImportFile (well, maybe not understand, but know what you are talking about :-)).

The code:
Me.Invoke(New cImportFile.NewFileProcessedEventHandler(Addressof OnNewFileProcessedEvent), new object() {source, e})

where exactly does that go? In the method:
    Public Sub OnNewFileProcessedEvent(ByVal source As Object, ByVal e As FileProcessedEventArgs)?

Once added, do I just go ahead and access the listbox properties normally?

I have been thrown back-and-forth so much in the past couple of weeks that I get very little time to do any work on this project (low priority). Every time I try to read up on delegates and threads and thread pooling and get a handle on it, something else comes up. Thanks for the help and your patience.
0
 
LVL 18

Assisted Solution

by:Priest04
Priest04 earned 2000 total points
ID: 19698422
Yes

Public Sub OnNewFileProcessedEvent(ByVal source As Object, ByVal e As FileProcessedEventArgs)

    If (Me.InvokeRequired) Then
        Me.Invoke(New cImportFile.NewFileProcessedEventHandler(Addressof OnNewFileProcessedEvent), new object() {source, e})
    Else
        ' now its safe to access form's controls
        Me.lvwProcessed.Items.Add("some item")
    End If

Goran
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19699561
THANK YOU!!! THANK YOU!!!
This is one of those very few times when I've asked for how to do something and have accomplished it without necessarily understanding exactly what it was I did. I definately need to get a firmer handle on delegates. But until then, you have certainly helped me.
0
 
LVL 18

Expert Comment

by:Priest04
ID: 19699912
You are welcome

Goran
0
 
LVL 15

Author Comment

by:dbbishop
ID: 19700726
Goran:

I posted another question at http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_22764524.html that you might be insterested in taking a look at dealing with threads. I'm learrning, but it is going slower than I hoped. Still need some help.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

It’s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following …
The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…
Suggested Courses
Course of the Month16 days, 15 hours left to enroll

864 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question