|
-
Nov 19th, 2010, 12:24 PM
#1
Thread Starter
Lively Member
Pass collection of objects to BackgroundWorker
I have an object of type Dictionary(Of Int16, Polygon) and which contains sometimes up to 15 or so Polygons that i am creating bitmap files with the Polygon. This can take like 20 seconds sometimes so i was trying to pass the full Dictionary to background worker as an argument but i get an issue when trying to access each individual Polygon inside of the Dictionary because the Polygons still belong to the UI thread. How can I access the Polygons inside the Dictionary with the backgroundworker?
Code:
Dim worker As New BackgroundWorker
AddHandler worker.DoWork, AddressOf MeasurePolygons
AddHandler worker.RunWorkerCompleted, AddressOf WorkerCompleted
worker.RunWorkerAsync(PolygonCollection)
that is how im calling the thread. PolygonCollection is the Dictionary(Of Int16, Polygon) that contains all the polygons that i will be creating a bitmap file out of. Thanks to anyway who can provide me with any assistance.
-
Nov 19th, 2010, 12:40 PM
#2
Re: Pass collection of objects to BackgroundWorker
Objects never "belong" to one thread or another unless they are local variables within a method that is executed as part of a thread. Even in that case, they only belong to the thread because local variables can't be accessed by any other method, so it is kind of owning by default. If objects truly belonged to one thread, and were not accessible by other threads, there wouldn't be any need for synchronization because it wouldn't be possible for two threads to be accessing the same object simultaneously...but that's a different story.
In your case, you don't need to pass the polygon collection around, as it would still be accessible by your WorkerCompleted method as long as it is in scope of the WorkerCompleted method (if it isn't in scope, then you still do need to pass it, but that seems unlikely). However, that doesn't answer your problem, it just casts doubt on the question. Since the polygons don't belong to any thread, the problem can't be that they still belong to the UI thread, so what is the actual problem?
My usual boring signature: Nothing
 
-
Nov 19th, 2010, 01:39 PM
#3
Thread Starter
Lively Member
Re: Pass collection of objects to BackgroundWorker
basically i have an InkCanvas where the user draws a shape, then clicks a button, and I use the strokes from the inkcanvas to create a Polygon and then I add that polygon to Private PolygonCollection As New Dictionary(Of Int16, Polygon) which is declared at the top of my class and accessed throughout.
this is what i have inside my MeasurePolygons Sub which is the DoWork of the BackgroundWorker i declared from in my first post.
Code:
Dim TempPolygonCollection As New Dictionary(Of Int16, Polygon)
TempPolygonCollection.Add(0, CType(e.Argument, Polygon))
Dim TempResponsesWoundMeasurements As New Dictionary(Of Int16, ResponsesWoundMeasurements)
TempResponsesWoundMeasurements(0) = New ResponsesWoundMeasurements(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
Dim BitmapCollection As New Dictionary(Of Int32, FileStream)
Try
Dim i As Int32 = 0
For i = 0 To TempPolygonCollection.Count - 1 'ctrlInk.Children.Count - 1
If TempPolygonCollection.ContainsKey(CShort(i)) Then
Dim rtb As New RenderTargetBitmap(CInt(800), CInt(600), 96D, 96D, PixelFormats.Default)
rtb.Render(TempPolygonCollection.Item(CShort(i)))
Dim encoder As New BmpBitmapEncoder
encoder.Frames.Add(BitmapFrame.Create(rtb))
End If
Next i
Catch ex As Exception
MsgBox(ex.ToString)
End Try
the error occurs at rtb.Render(TempPolygonCollection.Item(CShort(i))) and it says ""The calling thread cannot access this object because a different thread owns it"
thanks for your help. hopefully we r getting somewhere
-
Nov 19th, 2010, 01:53 PM
#4
Re: Pass collection of objects to BackgroundWorker
You pass a PolygonCollection to your BGW.RunWorkerAsync method, then you should cast e.Argument back to a PolygonCollection. Why are you casting it to Polygon?
Try to change these 2 lines
Code:
Dim TempPolygonCollection As New Dictionary(Of Int16, Polygon)
TempPolygonCollection.Add(0, CType(e.Argument, Polygon))
to this:
Code:
Dim TempPolygonCollection As Dictionary(Of Int16, Polygon) = TryCast(e.Argument, Dictionary(Of Int16, Polygon))
If TempPolygonCollection IsNot Nothing Then
' Do stuff here
End If
Let us have faith that right makes might, and in that faith, let us, to the end, dare to do our duty as we understand it.
- Abraham Lincoln -
-
Nov 19th, 2010, 01:56 PM
#5
Thread Starter
Lively Member
Re: Pass collection of objects to BackgroundWorker
yeah your right, i was just fooling with stuff and posted the wrong one by accident. that line should be
Code:
Dim TempPolygonCollection As New Dictionary(Of Int16, Polygon)
TempPolygonCollection = CType(e.Argument, Dictionary(Of Int16, Polygon))
but yeah, even with this like this, i still get the error at the rtb.Render(TempPolygonCollection.Item(CShort(i)))
-
Nov 19th, 2010, 02:53 PM
#6
Re: Pass collection of objects to BackgroundWorker
Having not used backgroundworker, I assumed that it worked like any other thread. That may have been an erroneous assumption, since a BGW is a component, but maybe not. An object should be an object. I wasn't even aware that there was a mechanism by which a thread COULD own an object, except for locking it with a syncloc or some other such synchronization mechanism. Is it possible that a different process has locked either one of the bitmaps (more likely), or the whole dictionary (unlikely)?
My usual boring signature: Nothing
 
-
Nov 19th, 2010, 03:02 PM
#7
Thread Starter
Lively Member
Re: Pass collection of objects to BackgroundWorker
well if you were to do something similar, would you use System.Threading? ive never used it before cause i was told backgroundworker was jsut the easier way of multithreading. But yeah, in the past, ive always had to pass any object created on the UI thread, to the background worker in order for it to have access to the object. Up until now i have only needed to do this with strings to use as parameters to execute a stored procedure that takes a while, but now that i'm trying to pass a collection, it doesnt like it. I was told on stackoverflow that it was the Polygons inside the dictionary that are being created on the UI thread and are not accessible on the backgroundworker...
-
Nov 19th, 2010, 03:16 PM
#8
Re: Pass collection of objects to BackgroundWorker
I think that the BGW is a very convenient way to do lots of threading tasks. If you were to just start into programming, then the BGW would be a very attractive solution. However, I got into multithreading prior to the introduction of the BGW, so I didn't start out using it. There is nothing that you can do with the BGW that you can't do with simple threading, but there are some things that are easier with the BGW. The key advantage that I see is that the BGW raises a couple events on the UI thread, such as the ProgressUpdated event, and so forth. You can certainly raise events from any other thread, but they would normally be raised on the same thread that raised them. While it takes little effort to raise them on the UI thread, it isn't very well documented, in my opinion, so it can be hard to figure out.
Of course, that has nothing to do with the problem at hand, except to explain that I haven't used the BGW for anything (I think, though I do remember trying it out for something). Perhaps the BGW packages data in a way that locks it? I'm not sure. In general, an object in memory, unless it was created as a local variable within a method, is located somewhere in the general process memory. Every thread has access to every such object because an address is just an address. For a thread to own an object, it would mean that the process would have to have a pool of memory set aside for that thread that no other thread can get to. Certainly could be done, I just wasn't aware that it was actually being done by anything except for synchronization.
I guess I am completely out of the realm of my experience when it comes to the BGW and how it handles objects. I create objects in the UI thread and use them in background threads routinely, or vice versa. If there are any issues with two threads modifying the object at the same time, then I use synchronization methods to restrict access, but those don't give out messages. Instead, a thread that found that changing an object was prevented, would simply wait until it became available, or do whatever else I chose, but it wouldn't cause an error message like you are seeing. Therefore, I assume that the BGW is different from normal threading, and shall step out of this conversation.
My usual boring signature: Nothing
 
-
Nov 19th, 2010, 07:57 PM
#9
Re: Pass collection of objects to BackgroundWorker
When multi-threading, you CAN NOT access the UI from a background thread. A WPF Polygon is a UIElement, therefore it cannot be access from a background thread. If you need to access the UI then you need to need to marshal a method call to the UI thread to do it. As the name suggests, a BackgroundWorker is for doing work in the background. Rendering Polygon's is inherently a foreground operation, so it obviously cannot be done on a background thread.
If you have lots of calculations to be done before the actual rendering part, THAT can be done on the background thread. Using the BackgroundWorker, you can do some work in the background and then update the UI intermittently by calling ReportProgress and handling the ProgressChanged event. You can also update the UI once the work is complete in the RunWorkerCompleted event handler. Both those events are raised on the UI thread, which is the whole point of the BackgroundWorker in the first place. There's no reason that you can't pass the Polygons to RunWorkerAsync and then pass an individual Polygon to ReportProgress. What you can NOT do is perform any operation that accesses a Polygon's handle in the DoWork event handler or any method called from the DoWork event handler. They are all executed on the background thread.
-
Nov 20th, 2010, 10:41 AM
#10
Re: Pass collection of objects to BackgroundWorker
Oops. WPF? ***! I haven't used WPF, and didn't recognize the Polygon as a UIElement. I was thinking that it was a drawing primitive like Rectangle in the System.Drawing namespace.
My usual boring signature: Nothing
 
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|