ok i am replying myself,
i am pretty sure that i found the reason of the problem. i would like others to confirm me that this is the case.
i have 2 global objects which are:
Private _piSDK As PISDK.PISDK = New PISDK.PISDK
Private _piSrv As PISDK.Server
and i am doing 3 different call to the arcvalue method with a point list. one from the main thread,
one with a standalone thread :
Private Sub btnStartFromThreadStandalone_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStartFromThreadStandalone.Click
_serverName = Me.txtServerName.Text
Dim th As New Thread(AddressOf GetPIData)
and one with the threadpool object:
Private Sub btnStartFromThreadPool_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStartFromThreadPool.Click
_serverName = Me.txtServerName.Text
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf GetPIDataFromTreadPool))
Private Sub GetPIDataFromTreadPool(ByVal state As Object)
what i found is that in my GetPIData, if i am creating the point list object like this:
Dim PIPointList As New PISDK.PointList
i have an error when adding points directly to the PIPointList with the add method with my global _piSrv objects:
but if i am doing
Dim PIPointList As PISDK.PointList 'without the NEW
and get the point list object with
PIPointList = _piSrv.GetPoints("Tag = 'BA:ACTIVE.1'")
so is it that mixing pi objects from different thread cannot be done, even of those objects (Private _piSDK As PISDK.PISDK = New PISDK.PISDK
Private _piSrv As PISDK.Server) are global?
The problem you are seeing here does not have anything to do with whether you use the 'New' keyword or not - it is rather a threading problem. A cross-thread marshaling problem, more specifically.
Because PI SDK in general is STA (single-threaded COM apartment) based, PI SDK methods can be invoked from one thread only. In a multi-threaded environment, you have to either marshal the objects you want to use in another thread, or have separate PI SDK hierarchies in each thread. Both approaches work. The first one is a little more work but consumes less memory.
If you don't have separate PI SDK hierarchies per thread, COM has to serialize the method invocation and the results - this is called cross-thread marshaling. When doing that, you essentially end up working with a "proxy" to the original object rather than the actual object itself. An example of that is when you call the PIPoints collection from the Server object, from a different thread than where the Server object was created.
With that said, you don't get a proxy by using global objects like you do: globals are just variables that are memory addresses, and when you build an object and stick it into a global, the same pointer you get from the creation gets dropped in the global. That means if another thread uses this global, it is just accessing that memory location and COM does not get a chance to substitute a proxy for the raw object pointer. So you are passing raw pointers to threads without marshaling, which will end in grief unless you are very careful. With the global, you are effectively bypassing COM; you would need to do something special to get the proxy.
Not only can this cross-thread marshaling cause problems (as in your case), it may also have a performance impact. The easiest solution is to make sure you instantiate a top-level PI SDK object that's local to each thread you need PI SDK calls from.
On the other hand, the GetPointsSQL method (could be the GetPoints method, for that matter) succeeds with that serialization because it's got some special code to handle the query through a background thread...
You can read more on this in the "Threading" article of the PI SDK Programming Reference. If you need more information on COM, threads, marshaling, etc., you might want to consider the book "Essential COM" from Don Box.
Hope this helps!
@Yannick: my "1-month flag" just raised for this one ...and I was wondering whether you got everything you needed or you need further assistance with this.
with the explications of ken and yours, i understand the issue and was able to work around it.
I was just wondering that with the arrival (and acception) of multi-core processors, and the availability of new parallel execution frameworks (Parallel Extensions to .NET framework for example, which is now included in .NET 4.0) the STA/COM nature of the PISDK will prevent us from taking full advantage of such frameworks.
Maybe (if the time is right) we could have some whitepapers about parallel execution and the PISDK ? These can then explain best practices and do's and don't's.