Illegal call out of MainThread is detected. Use `BeginInvokeOnMainThread`

Created at 13 May 2022, 14:21
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
ClickAlgo's avatar

ClickAlgo

Joined 05.02.2015

Illegal call out of MainThread is detected. Use `BeginInvokeOnMainThread`
13 May 2022, 14:21


All of our products at ClickAlgo use a standard threading model to open a UI form as shown below, this has been working fine for many years.

 

cTrader Desktop 4.2 Beta

try
{
    thread = new Thread(() =>
    {
        try
        {
            bootStrap = new Bootstrap(this);
            System.Windows.Forms.Application.Run(bootStrap.mainPanel);
        }
        catch
        {
        }
    });

    thread.SetApartmentState(ApartmentState.MTA);
    thread.IsBackground = true;
    thread.Start();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    this.Stop();
}

The only difference was that we were using an STA thread.

 

Now with cTrader Desktop 4.2, a warning is thrown stating that it is an illegal call out from the main thread and that we need to now use BeginInvokeOnMainThread

Is this now the only option we have for spawning a user interface?

A test using the new method is shown below which works fine, but there is an issue with events from the robot object passed across.

BeginInvokeOnMainThread(() =>
{
    try
    {
        bootStrap = new Bootstrap(this);
        System.Windows.Forms.Application.Run(bootStrap.mainPanel);
    }
    catch
    {
    }
});

I understand the warning, but does this mean we need to update all of our products to suppress this warning?

 

UPDATE

If the BeginInvokeOnMainThread method is used and a Robot object is passed in, many events are not working or work sometimes like closing positions Async.

 

 


@ClickAlgo
Replies

amusleh
16 May 2022, 10:44 ( Updated at: 16 May 2022, 10:45 )

Hi,

I'm not exactly sure what warning you are facing, this works fine for me:

using System;
using cAlgo.API;
using System.Threading;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class WinFormsTest : Robot
    {
        protected override void OnStart()
        {
            try
            {
                var thread = new Thread(() => System.Windows.Forms.Application.Run(new TestForm(this)))
                {
                    IsBackground = true
                };

                thread.SetApartmentState(ApartmentState.STA);
                thread.Start();
            }
            catch (Exception ex)
            {
                Print(ex);
            }
        }

        protected override void OnStop()
        {
            System.Windows.Forms.Application.Exit();
        }
    }
}

Regarding some events not working properly, in version 4.2 any API call must be executed from the main cBot/Indicator thread, you can't call a cBot/Indicator method/property from another thread, dispatch the call to main thread by using BeginInvokeOnMainThread method.

Please read our new guide for WinForms: WinForms - cTrader Automate API Documentation (spotware.github.io)


@amusleh

ClickAlgo
16 May 2022, 11:37

ok, thank you for your time.


@ClickAlgo

ClickAlgo
16 May 2022, 12:34

I have found the offending code that is causing this error, this will happen to a few of our products.

Leverage = robot.Account.PreciseLeverage

The robot object is passed into the assembly class that displays the UI, all the other events work fine, but when a call is made to retrieve account information, it throws the error below.

Illegal call out of MainThread is detected. Use `BeginInvokeOnMainThread`


@ClickAlgo

lisabeaney
16 May 2022, 14:03

RE:

I'm having the same problem so will follow this thread with interest !

ClickAlgo said:

I have found the offending code that is causing this error, this will happen to a few of our products.

Leverage = robot.Account.PreciseLeverage

The robot object is passed into the assembly class that displays the UI, all the other events work fine, but when a call is made to retrieve account information, it throws the error below.

Illegal call out of MainThread is detected. Use `BeginInvokeOnMainThread`

 


@lisabeaney

amusleh
16 May 2022, 14:23

Hi,

The warning message is there for notifying the user that the way h is using API is not correct, and the API calls should be made only from cBot/Indicator main thread not other threads.

For anyone who face same warning, we recommend you to use the BeginInvokeOnMainThread when you are using API members from other thread, that's the right way, otherwise you can face deadlocks or race condition.

Automate API is not thread safe, it should be only accessed via cBot/Indicator main thread, when you are using multiple threads dispatch the calls to API members to main cBot/Indicator thread for avoiding any inconsistency.

You can use decorator pattern, create a derived class from Robot or Indicator base classes, override all members to dispatch the calls to main thread by using BeginInvokeOnMainThread method.


@amusleh

ClickAlgo
16 May 2022, 16:36 ( Updated at: 17 May 2022, 11:58 )

Ahmad, is correct, we should be implementing the calls with more grace, the following call fixes the warning messages and works fine with CT 4.2

 


private void btnReverseSellers_Click(object sender, EventArgs e)
{
    _robot.BeginInvokeOnMainThread(() =>
    {
        try
        {
            foreach (var position in _robot.Positions.Where(x => (x.SymbolName == _robot.Symbol.Name)).Where(x => x.TradeType == TradeType.Sell))
            {
                position.Reverse();
            }
        }
        catch (Exception ex)
        {
            AlertPopUp msg = new Orders.AlertPopUp(ex.Message);
            msg.Show();
        }
    });
}

 


@ClickAlgo