I define a side-effect-free (pure) lambda expression in IronPython and assign it to a C# delegate. When invoking the delegate simultaneously from multiple threads i get exceptions of type AccessViolationException, NullReferenceException and FatalEngineExecutionError.
The occurance of the error is non-deterministic and it mostly takes several million iterations to provoke it, which says "race condition" to me. How can i avoid it?
The exceptions are only raised when running the process with x64 (x86 does not crash) and outside of the debugger. The test system is a Core I7 (8 threads) on Windows 7, .NET Framework 4.0 and IronPython 2.7.1.
Here's the minimal code to produce the error:
var engine = Python.CreateEngine(); double a = 1.0; double b = 2.0; while (true) { Func<double, double, double> calculate = engine.Execute("lambda a,b : a+b"); System.Threading.Tasks.Parallel.For(0, 1000, _ => { for (int i = 0; i < 1000; i++) { calculate(a,b); } }); Console.Write("."); }
Error message:
FatalExecutionEngineError was detected
Message: The runtime has encountered a fatal error. The address of the error was at 0xf807829e, on thread 0x3da0. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
Update: Even if the engine is declared as thread-local, it crashes after some time:
var calculate = new ThreadLocal<Func<double, double, double>>(() => Python.CreateEngine().Execute("lambda a,b : a+b"));
1. What is Lambda Function in Python? Lambda Function, also referred to as 'Anonymous function' is same as a regular python function but can be defined without a name. While normal functions are defined using the def keyword, anonymous functions are defined using the lambda keyword.
Modern C++ has lambda expressions. However, in C you have to define a function by name and pass a pointer — not a huge problem, but it can get messy if you have a lot of callback functions that you use only one time. It's just hard to think up that many disposable function names.
In Python, a lambda function is a single-line function declared with no name, which can have any number of arguments, but it can only have one expression. Such a function is capable of behaving similarly to a regular function declared using the Python's def keyword.
Simply put, a lambda function is just like any normal python function, except that it has no name when defining it, and it is contained in one line of code. A lambda function evaluates an expression for a given argument. You give the function a value (argument) and then provide the operation (expression).
This is likely due to a race condition within the ScriptEngine. Note that ScriptEngine.Execute returns a reference to a PythonFunction rather than a Func (it's due to C#'s dynamic behavior, that you can treat the result as a Func. I'm no expert on IronPython but looking at the source of PythonFunction, there is no indication whatsoever that it is threadsafe.
Have you tried replacing the 64 bit data type (double) with a 32 bit data type (float)? I do know that "A simple read or write on a field of 32 bits or less is always atomic" whereas a 64 bit field can have problems depending on the processor and the code. It seems like kind of a long shot but it is worth a try.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With