Je définis une expression lambda (pure) sans effet de bord dans IronPython et je l'affecte à un délégué C#. Lorsque j'invoque le délégué simultanément à partir de plusieurs threads, j'obtiens des exceptions de type Exception de violation d'accès , NullReferenceException y FatalEngineExecutionError (erreur fatale d'exécution du moteur) .
L'apparition de l'erreur n'est pas déterministe et il faut souvent plusieurs millions d'itérations pour la provoquer, ce qui me fait dire qu'il s'agit d'une "race condition". Comment puis-je l'éviter ?
Les exceptions ne sont levées que lors de l'exécution du processus avec x64 (x86 ne plante pas) et en dehors du débogueur. Le système de test est un Core I7 (8 threads) sous Windows 7, .NET Framework 4.0 et IronPython 2.7.1.
Voici le code minimal qui produit l'erreur :
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(".");
}
Message d'erreur :
Une erreur fatale (FatalExecutionEngineError) a été détectée.
Message : Le runtime a rencontré une erreur fatale. L'adresse de l'erreur est 0xf807829e, sur le thread 0x3da0. Le code d'erreur est 0xc0000005. Cette erreur peut être un bogue dans le CLR ou dans les parties non sûres ou non vérifiables du code utilisateur. Parmi les sources courantes de ce bogue figurent les erreurs de marshaling de l'utilisateur pour COM-interop ou PInvoke, qui peuvent corrompre la pile.
Mise à jour : Même si le moteur est déclaré comme étant local aux threads, il se plante au bout d'un certain temps :
var calculate = new ThreadLocal<Func<double, double, double>>(() => Python.CreateEngine().Execute("lambda a,b : a+b"));