mproit

Independent, parallel connections to servers. Threading, STA, MTA yet again...

Discussion created by mproit on Jul 10, 2012
Latest reply on Aug 6, 2012 by mhamel

I am still a bit confused about the threading with COM and STA. My goal is this, I want to have separate threads execute calls to a PI server in parallel (sometimes to the same server). I have read the Threading article in the PI SDK programming Reference and some other forum posts. I am programming in C#.

 

My understanding from reading the Threading article is that if each thread instantiates it's own PISDK objects, they will have their own, independent "heirarchies". However, I am finding that this is only the case if each thread is set to use STA apartment. However, this creates a bit of a performance hit if I create many threads.

 

If I don't explicitly set the threads to STA apartment (I'm assuming .NET defaults to MTA), each thread appears to be using the same connection to server, resulting in subsequent threads getting the connection to the server closed. My code sample below results in an exception saying "System.Runtime.InteropServices.COMException: Attempt to close server which is not open." Unless I uncomment the line setting the apartment to STA.

 

Finally, I have also tried passing the same (open) instance of the server to multiple threads and this results in no performance gain, so I am assuming that COM is serializing the calls under the hood.

 

How can I have multiple threads have independent connections to a server(s) and perform calls to those/that server in parallel?

 

 

 
      private static readonly DateTime DEFAULT_TIME = new DateTime(2012, 6, 18, 14, 07, 11);
      private PITime DefaultPiTime { get { return new PITime {LocalDate = DEFAULT_TIME}; } }

      [TestMethod]
      public void TestMultipleCallsMultiThreadMultiSdk()
      {
         int count = 10;
         _countdownEvent = new CountdownEvent(count);


         DateTime start = DateTime.Now;
         for (int i = 0; i < count; i++)
         {
            //ThreadPool.QueueUserWorkItem(o => TestMultipleCallsMultiThreadNewSdk());
            Thread t = new Thread(TestMultipleCallsMultiThreadNewSdk);
            //t.SetApartmentState(ApartmentState.STA);
            t.Start();
         }

         _countdownEvent.Wait();

         DateTime end = DateTime.Now;
         Console.WriteLine((end - start).TotalMilliseconds);
      }

      public void TestMultipleCallsMultiThreadNewSdk()
      {
         PISDK.PISDK sdk = new PISDK.PISDK();

         try
         {
            Server server = sdk.Servers.DefaultServer;

            server.Open();

            try
            {
               GetABunchOfData(server);
            }
            finally
            {
               server.Close();
            }
         }
         finally
         {
            sdk = null;
            _countdownEvent.Signal();
         }
         
      }

      private void GetABunchOfData(Server srv)
      {
         PIPoint point = GetDefaultTestPoint(srv);
         PIValues values = point.Data.PlotValues(DefaultPiTime,
                                                 new PITime { LocalDate = DEFAULT_TIME.AddDays(5) }, 1000);
      }

 

 

 

 

 

Outcomes