question

Upvotes
Accepted
3 1 1 1

"Objects must be created by the same thread" in Eikon API

I created Eikon API in C# using several examples for time series data found on this website. My application has a GUI and if I specify certain dates and run the application, data extraction works fine. However, if I try to extract more data without exiting the application, I get an error saying "Objects must be created by the same thread". I have read other posts saying that Eikon should be used with single-threaded architecture and, unfortunately, I know very little about how threading works. Ic can see tha the thread changes between each request (

var thr = Thread.CurrentThread.ManagedThreadId;). However, is there any way I can "reuse" the same thread for multiple requests or what would be a likely solution in this case?

eikoneikon-data-apieikon-com-apic#
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
Accepted
39.3k 76 11 27

@maria.razmyslovich

Using BackgroundWorker class should be fine if you only need to retrieve data from Eikon once over the lifetime of your application. If you need to retrieve data from Eikon more than once, then you cannot use the BackgroundWorker class because the BackgroundWorker object may create a new thread each time you execute RunWorkerAsync method, which then means your data retrieval from Eikon is happening on multiple threads, which is exactly what you need to avoid. If you must retrieve data from Eikon on a non GUI thread, then you need to do it on a single thread that should be running as long as your application may need data from Eikon.
I'm afraid I completely fail to see the point in moving data retrieval onto a non GUI thread. BackgroundWorker class was designed for moving a time consuming synchronous operation out of the GUI thread. When you use Eikon .NET API the data retrieval is asynchronous. It does not block the GUI thread. If you move data retrieval to a background thread your code will get much more complicated, as you'll need to create and manage the thread in your code, you will need to marshall the data you retrieved from Eikon to the GUI thread, if you want to display it. All for absolutely no benefit. Multithreading is a complex subject with tons of underwater rocks and since you mentioned you had practically no experience with it I strongly suggest you stay away from managing multiple threads.
You mentioned you had some issues with the data retrieval on the GUI thread. Perhaps it's better to look into these issues? They may be easier to address. Or they may have nothing to do with running data retrieval from Eikon on the GUI thread, in which case moving data retrieval to a background thread would not resolve them. Would you care to describe what you experienced?

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
4.6k 26 7 22

@maria.razmyslovich it is very hard to recommend anything meaningful without looking at the code, but there are a few things I can suggest:

  1. Add [STAThread] attribute to you app's entry point;
  2. Make sure your data requests are performed on the same thread your UI is running, i.e. do not start a separate thread for each new request.
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Thanks a lot, @Zhenya Kovalyov , the second suggestion about making everything run on the same thread as UI solved the problem of sending multiple requests to Eikon. However, does that mean that Eikon API essentially is not meant for applications with GUI where it is common to let this type of work be processed by a background thread?

@maria.razmyslovich inability to use full threading with this API is a side effect of the design of distribution model that we have chosen - registration free COM.

@maria.razmyslovich

I assume you're using Eikon COM APIs, right? These APIs are primarily used in GUI applications. Eikon COM APIs must be used on a single thread and it's best to use them on the GUI thread. The reason you may want to use the background thread is primarily to perform tasks that may take time and that if performed on the GUI thread might hang the GUI. Eikon COM APIs implement asynchronous behavior meaning that the GUI will not hang while Eikon COM objects perform their tasks such as retrieving data.

@Alex Putkov. no, this is a .NET Time Series API case, apparently

Show more comments

If you really need to do this, it's possible to use Eikon COM APIs on a background thread. However in this case all Eikon COM objects must be created on this single background thread. And you need to ensure Windows messaging pump is running on this background thread, otherwise COM objects will not receive any events. Windows messaging pump is always automatically started on the GUI thread, but not on any background threads.

Upvotes
3 1 1 1

@Alex Putkov. yes, I think we would like to try implement Eikon .NET API on a background thread, because we tried to make everything run on the UI thread and that basically resulted in some suboptimal outcomes.

In our application we implement a BackgroundWorker that basically does data extraction through DoEvent and we update the UI using the ReportProgress method.

Data Extraction itself happens in the object called ReutersAPI shown below, which is basically a copy of the standard example provided on this website. BulkDataRequestSettings and BulkDataRequest are implemented as shown here:

https://community.developers.refinitiv.com/storage/attachments/369-bulkdatarequestcs.txt

So, do you have any suggestions as to how I can make the windows message pump run on the background thread given that it is the backgroundWorker that calls this class?
Is it something like

Thread.CurrentThread.IsBackground = true; ? Where should I then set it?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Windows.Threading;
using System.Threading;
using ThomsonReuters.Desktop.SDK.DataAccess;
using ThomsonReuters.Desktop.SDK.DataAccess.TimeSeries;
using DataLayer.ReutersApi.MarketDataDefinitions;
using System.Data;
namespace DataLayer.ReutersApi
{
                
publicclassReutersApi
    {
                
publicstatic IDataServices Services { get; privateset; }
privatestatic ITimeSeriesDataService timeSeries;
privatestaticreadonly DispatcherFrame Frame = new DispatcherFrame();
public DateTime _referenceDate;
publicstatic BulkDataRequestSettings _settings;
 
               
public ReutersApi()
        {
                
        }
 
               
publicvoid SetReferenceDate(DateTime referenceDate)
        {
                
            _referenceDate = referenceDate;
        }
 
               
publicvoid InitialiseSessionAndService()
        {
                
 
               
var thread = Thread.CurrentThread.ManagedThreadId;
 
               
            InitializeDataServices("TimeSeries");
 
               
            Frame.Continue = true;           
            Dispatcher.PushFrame(Frame);
        }
 
               
publicstaticvoid StopMessagePump()
        {
                
 
               
            Frame.Continue = false;
        }
 
               
privatestaticvoid InitializeDataServices(string appName)
        {
                
            DataServices.Reset();
            Services = DataServices.Instance;
            Services.StateChanged += ServicesOnStateChanged;
            Services.Initialize(appName);
            InitializeTimeseries();
        }
 
               
privatestaticvoid ServicesOnStateChanged(object sender, DataServicesStateChangedEventArgs dataServicesStateChangedEventArgs)
        {
                
        }
 
               
privatestaticvoid InitializeTimeseries()
        {
                
            timeSeries = DataServices.Instance.TimeSeries;
            timeSeries.ServiceInformationChanged += timeSeries_ServiceInformationChanged;
 
               
        }
 
               
privatestaticvoid timeSeries_ServiceInformationChanged(object sender, ServiceInformationChangedEventArgs e)
        { 
            TimeSeriesRequest();
        }
 
               
publicstaticvoid TimeSeriesRequest()
        {
                
 
               
            BulkDataRequest Request = new BulkDataRequest(_settings);
            Request.Send();
        }
 
               
publicvoid SetRequestSettings (BulkDataRequestSettings settings)
        {
                
            _settings = settings;
        }


icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
3 1 1 1

@Alex Putkov. thanks for your answer! That is exactly what I thought - that with BackgroundWorker one can only retrieve data from Eikon once over the lifetime of the application. We moved data retrieval to the background thread, because the GUI thread is used to display log / status of what is happening in the application at different times and also because we have several other APIs that are not asynchronous. But at least now I understand how Reuters' API works, so I can think about how to best rewrite the code for the application. Once again, thanks for your help!

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.