Search code examples
javamatlabmatlab-figurematlab-deploymentmatlab-compiler

Matlab Compiler SDK plot waitforFigures function multiple threads


I have created a simple plot with matlab and created a java jar with matlab compiler sdk.

I can run the java function created by matlab and see my plot.

I wanted to create multiple plots and started the function in separate threads. It works. But if i start my java function for creating multiple plots, the waitforFigure() method of the first thread is waiting for the other plots to be closed too. So my first thread does not continue and blocks till the other plots who are created after it also are closed.

I thought instantiating a Object of the Java class, produced by the Matlab compiler SDK creates a new Matlab compiler runtime?!. Why is the waitforFigure method waiting for the other plots too, if it is run on seperate thread?

Here is my function runFunction of the RunAlgorithm class i created. The runFunction methods instantiates the Matlab Compiler SDK created Class, Class1. Its the default name of the class. The thePlot function is the matlab code running in the Matlab runtime and plots my data.

void runFunction( MWNumericArray x1, MWNumericArray y1, MWNumericArray z1) throws MWException {


Class1 thePlot = new Class1;

    /* Number of points to plot */
    try {


        /* Plot data */
    thePlot.runAlgorithm( x1, y1, z1);
    thePlot.waitForFigures();

    }

    catch (Exception e) {
        System.out.println("Exception: " + e.toString());
    }

    finally {
        /* Free native resources */
        MWArray.disposeArray(x1);
        MWArray.disposeArray(y1);
        MWArray.disposeArray(z1);
        if (thePlot != null)
            thePlot.dispose();
    }
}

Here my simple thread how it executes the Function containing my Matlab class. I instantiate the RunAlgorithm class, read data from file, and pass it converted to MWNumericArray to the runFunction method. In my runFunction method there is the waitforFigures method blocking.

Thread t1=new Thread() {
           public void run() {


        RunAlgorithm a = new RunAlgorithm();
        RunAlgorithm.Measurements n = null;

        try {
            n= a.readFile(selectecValue);
            System.out.println("File REad");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {

            a.runFunction(n.mX, n.mY, n.mZ);
        } catch (MWException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         }
            };
            t1.start();

Basically i read a csv File, parse my Data in to MWnumericArray, and pass it to the RunAlgorithm class. That Class internally creates the Class1 Object with the runFunction and plots my Matlab- Plot with Matlab runtime.

EDIT:

If i run my application twice. The waitforFigure method is just waiting for the threads generated by one application. That would mean, the matlab runtime is run once with the application, independent from the threads i created?

So the Class1 instantiation is not starting a new matlab runtime everytime?

EDIT: If i compile my matlab code as Singleton,then my plot is refreshed. That would mean, the instatiation of my Class1 Object is starting a new matlab runtime ?


Solution

  • I had a look into your problem and tried to create a Matlab jar on my machine. However, for some reason, creating a jar file failed, so instead I created a dll for .net application. The underlying principle should be similar anyway.

    Here is a snap of the constructors found in the generated C# code:

    private static MWMCR mcr= null;
    static Plotter()
    {
      if (MWMCR.MCRAppInitialized)
      {
        try
        {
          /* a lot of codes here but deleted to make what is important stands out */
          mcr= new MWMCR("",
                         ctfFilePath, embeddedCtfStream, true);
        }
        catch(Exception ex) { //some code here }
      }
    }
    
    public Plotter()
    {
      if(ex_ != null)
      {
        throw ex_;
      }
    } 
    

    And the drawplot() method which tells the Matlab runtime to run the packaged M-script.

    public void drawplot()
    {
      mcr.EvaluateFunction(0, "drawplot", new MWArray[]{});
    }
    

    As you can see, the MWMCR class is the actual Matlab instance that runs the M-script and it is a static object. Therefore, no matter how many Plotter or Class1 is instantiated, there is only one Matlab instance. Multiple mcr.EvaluateFunction requests are queued and executed one after one. Therefore, theoretically running multiple Matlab scripts simultaneously is not possible without having two MWMCR objects generated, which means you will need multiple instances of your java assembly (experimentally confirmed).


    In your case, all figures are plotted by the same instance of MWMCR, and WaitForFiguresToDie or waitForFigures() checks for any unclosed figures plotted by MWMCR.

    public void WaitForFiguresToDie()
    {
        mcr.WaitForFiguresToDie();
    }
    

    A solution I can propose to you is to include an empty Matlab code (EmptyCode()) in your jar package. Then implement something similar to the following in your java code:

    void runFunction()
    {
        Class1 thePlot = new Class1;
        Thread t1=new Thread() {
           public void run() {
               Class1 thePlot = new Class1;
               thePlot.waitForFigures();
               }
        }
        Thread t2=new Thread() {
           public void run() {
               Class1 thePlot = new Class1;
               thePlot.waitForFigures();
               }
        }
        thePlot.waitForFigures();
        t1.start();
        t2.start();
    
        //your java code
    
        thePlot.EmptyCode();
        thePlot.waitForFigures();
    }