Forum Discussion

FICO's avatar
FICO
Community Manager
6 years ago

Redirect stream in C# with parallel (independant) mosel instances

I have written a c# method "MyMethod" solving a given mosel model and getting solution.

At the beginning of "MyMethod", I have :

var mosel = XPRM.Init();
 
mosel.SetDefaultStream(XPRMStreamType.F_OUTPUT, Console.Out);
mosel.SetDefaultStream(XPRMStreamType.F_ERROR, Console.Out);

If i call "MyMethod" twice without calling "mosel.Dispose()", I get this error the second time :

'Unable to set default stream F_ERROR to 'dotnet:stderr''

I understand that calling the Dispose method must be done at the end of the process.

But how to avoid problem if I call my method in a "parallel for" ? For example :

Parallel.For(0, 10, i =>
{
        MyMethod();
});

I always have the error when redirecting the stream.

EDIT : I know that by default these stream are displayed to standard out. It is only a simple example to explain my problem. In reality these streams are redirected in both log file and console using log4net.

4 Replies

  • FICO's avatar
    FICO
    Community Manager

    The error here is generated when XPRMsetdefstream returns nonzero; that usually means a model exists and thus the default streams can't be redirected. The best way to solve this would be to initialize Mosel before entering the parallel code and dispose it once all the threads have finished.

  • FICO's avatar
    FICO
    Community Manager

    So you advice to create only one XPRM object and to share it between all the threads. Is this correct ?

    But in this case, all the threads have to write log at the same place.

    So a code where each thread writes a specific log file is not possible. For example :

    Main method :

    Parallel.For(0, 10, i =>
    {
           MyMethod(i);
    });

    MyMethod(int i) :

    XPRM mosel = XPRM.Init();
     
    string fichierLog = Path.GetFullPath($@"LogMosel{i}.txt");
    StreamWriter sw = new StreamWriter(fichierLog, false);
    XPRMIOCallbackOutputText callback = (XPRMModel model, object obj, string line) =>
    {
           Console.Write(line);
           sw.Write(line);
    };
     
    mosel.SetDefaultStream(XPRMStreamType.F_OUTPUT, mosel.CreateIOCallback(callback));
    mosel.SetDefaultStream(XPRMStreamType.F_ERROR, mosel.CreateIOCallback(callback));
  • FICO's avatar
    FICO
    Community Manager

    In Mosel, there are global output/error streams shared by all models, that you configure using XPRM.SetDefaultStream, but each model has its own output/error streams that you can set separately using XPRMModel.SetDefaultStream. I would recommend you call XPRMModel.SetDefaultStream to capture the output of each model separately. The only output that would then get written to the 'global' streams would be system-wide errors and failures to load models.

  • FICO's avatar
    FICO
    Community Manager

    Thank you very much, it is exactly what I was looking for.

    Dont know why I have not looked for this method for XPRMModel objects.