I am using a library called muParserNET in my application. muParserNET is a function parsing library, and my application is calling it multiple times from different threads.
muParserNET consists of a C++ (unmanaged) dll with a managed C# wrapper. In this wrapper, it passes the pointer to an error handling routine to the unmanaged library on initialisation.
i.e. within the Parser class we have this function:
/// <summary>
/// Error handler. It loads the ParserError exception.
/// </summary>
private void ErrorHandler()
{
IntPtr ptrMessage = MuParserLibrary.mupGetErrorMsg(this.parserHandler);
string message = Marshal.PtrToStringAnsi(ptrMessage);
IntPtr ptrToken = MuParserLibrary.mupGetErrorToken(this.parserHandler);
string token = Marshal.PtrToStringAnsi(ptrToken);
string expr = this.Expr;
ErrorCodes code = (ErrorCodes)MuParserLibrary.mupGetErrorCode(this.parserHandler);
int pos = MuParserLibrary.mupGetErrorPos(this.parserHandler);
// lança a exceção
throw new ParserError(message, expr, token, pos, code);
}
Here is the initialisation of the parser object, in managed code. it happens on the last line of this function:
public Parser()
{
// inicializa o parser
this.parserHandler = MuParserLibrary.mupCreate(0);
// inicializa o dicionário com as variáveis
this.vars = new Dictionary<string, ParserVariable>();
// inicializa as listas de delegates
this.identFunctionsCallbacks = new List<ParserCallback>();
this.funcCallbacks = new Dictionary<string, ParserCallback>();
this.infixOprtCallbacks = new Dictionary<string, ParserCallback>();
this.postfixOprtCallbacks = new Dictionary<string, ParserCallback>();
this.oprtCallbacks = new Dictionary<string, ParserCallback>();
// inicializa o delegate de factory
this.factoryCallback = new ParserCallback(new IntFactoryFunction(this.VarFactoryCallback));
// ajusta a função de tratamento de erros
MuParserLibrary.mupSetErrorHandler(this.parserHandler, this.ErrorHandler);
}
On running this code, sporadically, on calls to evaluate functions (so sometime after initialisation of the object) I get this error:
A callback was made on a garbage collected delegate of type 'muParserNET!muParserNET.ErrorFuncType::Invoke'
ErrorFuncType is the type of this.ErrorHandler passed above using MuParserLibrary.mupSetErrorHandler.
My understanding is that since the error handler function is not used after its pointer is passed to unmanaged code, it gets garbage collected. How can I prevent this from happening?
More information based on the first reply: The parser object is created inside a calculation routine which may be running simultaneously on up to 8 separate threads, typically. The object is created and disposed of within the calculation routine. For this reason, I didn't want to create the parser object as static as it would limit me to only one thread using the parser at any one time.