Multi-Threading Consideration for NinjaScript

<< Click to Display Table of Contents >>

Navigation:  NinjaScript > Educational Resources >

Multi-Threading Consideration for NinjaScript

Previous page Return to chapter overview Next page

Multi-Threading Overview

With the introduction of multi-threading in NinjaTrader special considerations should be made when programming your NinjaScript objects. Multi-threading basically allows NinjaTrader to take advantage of multi-core CPUs commonplace in modern computing to do multiple tasks at the same time.  While this has many advantages for multi-tasking, it can cause new types of issues you may have not needed to consider before.  This page was designed to serve as a high-level overview of some of the most common scenarios that can arise due to multi-threading, but should not be considered an exhaustive list.

 

Using A Dispatcher

Depending on your CPU configuration, the NinjaTrader application will usually consist of multiple main UI threads, where various features like Charts or NinjaScript objects run, along with a number of background worker threads where events such as market data updates will be distributed throughout the product.  In principle, an object can only access information related to objects that exist on the same thread.  It is possible (and quite likely), that the thread which a NinjaScript object is running will not be the same thread as the event which is calling the object.  In cases where you need to access objects on the UI from a NinjaScript objects calling event thread, a dispatcher can be used.

 

Note:  As a best practice, you should always make sure to use Dispatcher.InvokeAsync() to ensure your action is done asynchronously to any internal NinjaTrader actions.  Calling the synchronous Dispatcher.Invoke() method can potentially result in a deadlock scenarios as your script is loaded.

 

 

ns


if (State == State.Historical)
{
  if (ChartControl != null)
  {
    // add some text to the UserControlCollection through the ChartControls dispatcher
    ChartControl.Dispatcher.InvokeAsync(new Action(() => {
        UserControlCollection.Add(new System.Windows.Controls.TextBlock {
          Text = "\nAdded by the ChartControl Dispatcher."
        });
    }));
  }
}

 

 

Thread Access

Since market data is distributed across the entire application by a randomly assigned UI thread, there is no guarantee that your object will be running on the same event thread that is calling the object. Therefore it is recommend that you call Dispatcher.CheckAccess() in order to test if you truly need to dispatch the requested action.

 

ns


// check if the current object is already on the calling thread
if (Dispatcher.CheckAccess())
{
  // execute action directly
  action(args);
}
// otherwise run the action from the thread that created the object
else
{
  // dispatch action to calling thread
  Dispatcher.InvokeAsync(action, args);
}

 

 

Cross Thread Exceptions

When accessing objects included on the UI, you may receive the following error if you attempt to access a certain property/method from the wrong thread:

 

"Error on calling 'OnBarUpdate' method on bar 0: You are accessing an object which resides on another thread. I.E. creating your own Brush without calling .Freeze(), or trying to access a UI control from the wrong thread without using a Dispatcher"

 

This error can be avoided by invoking the Dispatcher used on the appropriate UI thread.

 

Access Violation Exception

Should you be using custom resources like text files, static members, etc. it is important to protect your resources from concurrent access. If NinjaTrader tried to use the resource at the same time you would run into errors similar to this one:

 

8/20/2010 12:14:29 PM|3|128|Error on calling 'OnBarUpdate' method for strategy 'SampleStrategy/1740b50bfe5d4bd896b0533725622400': The process cannot access the file 'c:\sample.txt' because it is being used by another process.

 

ns


private object lockObj = new object();
 
private void WriteFile()
{
  // lock a generic object to ensure only one thread is accessing the following code block at a time
  lock (lockObj)
  {
      string filePath = @"C:\sample.txt";
      using (System.IO.FileStream file = new System.IO.FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None)
      {
        // write something to the file...
 
        // be sure to flush the buffer so everything is written to the file.
        file.Flush();
 
        // The "using" block implicitly closes the FileStream object,
        // giving other threads access to the file
      }
  }
}