|
-
Jun 15th, 2009, 11:42 AM
#1
Thread Starter
New Member
Simple Problem Using Invoke
I am working on adding multi-threading to my application. I have done two applications using multi-threading following a tutorial of sorts, and modifying the code to "get my feet wet."
This is the first time I am trying multi-threading within my own application, and I feel I should be beyond this type of problem, but after a 3 hour search on the forums, I can not find a solution, so I am posting this thread.
The section of code with the error
vb.net Code:
Imports System.Threading
Imports SldWorks
Imports SwConst
Imports System
Imports System.Windows.Forms
Imports System.Globalization
Imports System.Object
Imports System.Math
Public Parent As GCode
Public Sub Initialize(ByVal oParent As Object)
'oGCode = oParent
Parent = oParent
.
.
.
bResults = Parent.invoke(Parent.cSetTransform, swMathTransform)
End Sub
The error is:
Error 1 'invoke' is not a member of 'ToyodaMill.GCode'.
the Gcode class is as follows:
vb.net Code:
Imports System.Threading
Imports SldWorks
Imports System.IO
Imports System.Text
Public Class GCode
ReadOnly oTransformLock As New Object
Dim swTransform As MathTransform
Dim sTransformName As String
Delegate Function dSetTransform(ByVal Transform As SldWorks.MathTransform)
Public cSetTransform As dSetTransform
Public Function SetTransform(ByVal Transform As SldWorks.MathTransform) As Boolean
Monitor.Enter(oTransformLock)
SetTransform = True
Try
swTransform = Transform
Catch ex As Exception
SetTransform = False
Finally
Monitor.Exit(oTransformLock)
End Try
End Function
Please help
Last edited by Hack; Jun 15th, 2009 at 11:52 AM.
Reason: Added Highlight Tags
-
Jun 15th, 2009, 11:53 AM
#2
Re: Simple Problem Using Invoke
-
Jun 15th, 2009, 01:43 PM
#3
Re: Simple Problem Using Invoke
Firstly, turn Option Explicit On (Make sure, option strict is also on).
your parameter, oParent, is an Object. Your object 'parent' (not a good name, probably) is of type GCode. Gcode cannot be assigned from the parameter oParent. You want to cast (Cast, DirectCast or TryCast the passed parameter to the correct type).
There is no Invoke method on your object GCode. Why not simply call your SetTransform method directly? It seems you may be overcomplicating things; there's no need (from what I can see) to do any invocation.
"Ok, my response to that is pending a Google search" - Bucky Katt.
"There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
"Before you can 'think outside the box' you need to understand where the box is."
-
Jun 15th, 2009, 02:54 PM
#4
Thread Starter
New Member
Re: Simple Problem Using Invoke
option explicit is on,
option strict is also on,
I don't like the use of the word Parent either. My original code used oGCode instead. I switched because the test code which I was successful in multi-threading used the name Parent, and I thought it might be important. I will switch it back eventually.
This code work fine when calling the function directly; However it is very calculation intensive. I therefore am trying to make the calculation part be on a separate thread from the UI. That way the dialog box will remain responsive while the program is running through its calculations.
-
Jun 15th, 2009, 02:57 PM
#5
Re: Simple Problem Using Invoke
The only possible reason I see to be trying to invoke SetTransform is if Transform is a function that you need to have run on the UI thread. That would be the case if Transform alters the UI, but otherwise it seems unlikely.
There is an alternative, which I have mentioned several times, but apparently I have never actually spelled it out, so I will do so here:
I have used this concept in several places where I want a function run in a different thread (generally the UI thread, but it isn't necessary).
1) Save the SynchronizationContext. Usually I am working in a class that runs a background thread. This context is common to a thread, not a class, so I always store it as a shared value:
Private Shared uiContext As System.Threading.SynchronizationContext
2) I then capture the UI context in the constructor using something like this:
Code:
If uiContext Is Nothing Then
uiContext = System.Threading.SynchronizationContext.Current
End If
3) Having the synchronizationContext of the UI thread, it is now possible to post calls to subs that will be run in the UI thread, though there are some caveats as to what the sub looks like:
Code:
uiContext.Post(AddressOf <my sub>,state as Object)
Note that Post will be an asynchronous call, while Send would be synchronous. The sub has to take a single argument of type Object, which is the state argument of the Post call. This can be awkward, but heck, an Object can be ANYTHING, so just put what you need in it. If you need to call a sub that has multiple arguments, make a dummy sub that takes all the arguments as members of a class, then have that dummy sub unpack the arguments from the class and call the proper sub with the arguments. The key is that the sub called by the Post will be called in the UI context.
My usual boring signature: Nothing
 
-
Jun 15th, 2009, 02:58 PM
#6
Re: Simple Problem Using Invoke
Oops, I had two conversations between starting that post and posting it, so I missed your reply. The bulk of it might still help, though.
My usual boring signature: Nothing
 
-
Jun 15th, 2009, 03:14 PM
#7
Re: Simple Problem Using Invoke
Option Strict is ON? With this code?
Public Parent As GCode
Public Sub Initialize(ByVal oParent As Object)
Parent = oParent
...
I'm sorry, but I can't believe that. You should have an error on the Parent = oParent line.
If you want the calculation to run in a different thread then why not create a thread for it to run on? Although Shaggy has a good point (The synchronizationContext is a good tool), unfortunately you haven't shown anywhere that a thread is being created.
There are various methods of encapsulation, but it's very application specific. But creating a thread is extremely simple. What you may want to do is encapsulate the thread within a class, with a 'calculate' method which actually creates a thread and raises an event when complete.
Code:
Private Class Calculator
Public Event WorkComplete()
Public Sub Calculate()
Dim t As New System.Threading.Thread(AddressOf CalculateThread)
t.IsBackground = True
t.Start()
End Sub
Private Sub CalculateThread()
' Do The Work
RaiseEvent WorkComplete()
End Sub
End Class
If you want to pass an object to the thread, then you'd use a parameterized Thread:
Code:
Private Class Worker
End Class
Private Class Calculator
Public Event WorkComplete()
Public Sub Calculate(ByVal workParameters As Worker)
Dim t As New System.Threading.Thread(New Threading.ParameterizedThreadStart(AddressOf CalculateThread))
t.IsBackground = True
t.Start()
End Sub
Private Sub CalculateThread(ByVal obj As Object)
Dim w As Worker = TryCast(obj, Worker)
If w Is Nothing Then
' Do something with a bad worker object
End If
' Do The Work
RaiseEvent WorkComplete()
End Sub
End Class
"Ok, my response to that is pending a Google search" - Bucky Katt.
"There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
"Before you can 'think outside the box' you need to understand where the box is."
-
Jun 15th, 2009, 03:24 PM
#8
Thread Starter
New Member
Re: Simple Problem Using Invoke
In this case swTransform is a piece of data, (it is a SolidWorks Math Transform Object which contains the zero point with respect to the actual origin, as well as the rotational, translational, and scaling data.)
SetTransform and GetTransform are functions to get and set the variable swTransform. This data is on the UI thread, and is used in both the UI (locating the origin) and the calculation thread.
I asked in another post about storing the data on a separate thread other than the UI and calculation thread, but from the comments, I do not believe it would be of any benefit, so I put the data on the UI thread.
I am not certian about the synchronization, but I will give it a try.
-
Jun 15th, 2009, 03:32 PM
#9
Re: Simple Problem Using Invoke
The data is not on any thread. Data is not tied to a thread, which is why you have that Monitor in there. Any thread can access any data that is within scope, so multiple threads could alter or access the same data item at any time, thereby causing race conditions...potentially. Don't be thinking about a thread as owning data (other than local variables tied to a single routine), or you will cause yourself trouble down the road.
SynchronizationContexts are both useful, simple, and poorly documented. If a thread calls a sub, the sub will run in the thread that called it. To have a thread cause a sub to run in a different context, the SynchronizationContext is really nice. I was actually using this technique to call a sub that would raise events. If the thread called the sub directly, the event would be raised on the background thread, which is not what I wanted.
My usual boring signature: Nothing
 
-
Jun 15th, 2009, 03:34 PM
#10
Re: Simple Problem Using Invoke
Something else to think about: you don't 'store' data on a thread - threads are simpler than that. Any data accessible from one thread, is available to another thread (depending on scope).
You have used a Monitor, so you obviously have something in mind to ensure synchronicity. If you hold your (transform) data within the object which creates your thread it's probably going to be easier to synchronize those objects with the UI and the calculation.
"Ok, my response to that is pending a Google search" - Bucky Katt.
"There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
"Before you can 'think outside the box' you need to understand where the box is."
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
|