2015-10-17 3 views
0

Voici un exemple de programme (vous aurez besoin de la bibliothèque Enterprise pour l'exécuter). J'exécute 100 tâches dans une boucle, elles enregistrent un message dans le journal des événements. Je stocke la tâche générée dans le tableau des tâches et je la surveille simplement dans une boucle while.Obtention de l'objet EnterpriseLibrary Erreur LogWriter dans la boucle Tâches

Le problème est sur 100, les tâches aléatoires échouent et donnent l'erreur ci-dessous. D'après ce que je comprends, les tâches ont leur propre état, donc elles ne doivent pas interférer les unes avec les autres et la méthode Logger est statique, donc je ne sais pas où mon objet est jeté.

  1. Pourquoi l'objet Logger est-il éliminé s'il est statique?

  2. si je mets LOCK (objet) autour de mon code de l'enregistreur dans Task.Run() que cela fonctionne très bien. Est-ce une bonne idée ?

Erreur

à Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter.get_SyncLock() à Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter.ExecuteReadOperation (Action readOperation) chez Microsoft .Practices.EnterpriseLibrary.Logging.LogWriter.Write (journal LogEntry) à Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write (journal LogEntry) à WW.Test.TasksLoggingTest.b__1() dans c: \ tfs \ Report \ WWTest \ TasksLoggingTest.cs: ligne 7 9 à System.Threading.Tasks.Task`1.InnerInvoke() à System.Threading.Tasks.Task.Execute()

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 
using Microsoft.Practices.EnterpriseLibrary.Logging; 
using System.Web.Hosting; 

namespace Test 
{ 
    public class TasksLoggingTest 
    { 
     bool flag = true; 
     Thread T; 
     public static volatile bool IsWorkStarted = false; 

     public void Start() 
     { 
      while(flag) 
      { 

       try 
       { 
        if (IsWorkStarted == false) 
        { 

         IsWorkStarted = true; 

         T = new Thread(DoWork); 
         T.IsBackground = true; 
         T.Start(); 
        } 
       } 
       catch(Exception e) 
       { 
        Console.WriteLine("Error starting thread"); 
       } 
       finally 
       { 
        Thread.Sleep(TimeSpan.FromSeconds(5)); 
       } 
      } 
     } 


     public void DoWork() 
     { 
      try 
      { 

       Task<int>[] _tempTaskList = new Task<int>[100]; 

       for (int i = 0; i < 100; i++) 
       { 
        int localI = i; 


        _tempTaskList[localI] = Task.Run(() => 
        { 


         Logger.SetLogWriter(new LogWriterFactory().Create(), false); 

         var logEntry = new LogEntry 
         { 
          Severity = TraceEventType.Information, 
          Message = "Job Started :", 
         }; 

         logEntry.Categories.Clear(); 
         logEntry.Categories.Add("Send.To.EventLog"); 
         Logger.Write(logEntry); 


         return 0; 
        }); 
       } 


       bool IsAnyTaskPending = true; 
       int noOfTasks = 0; 

       while (IsAnyTaskPending == true) 
       { 

        foreach (var t in _tempTaskList) 
        { 
         // Remove Completed Tasks from TaskList 
         if (t != null && t.Status == TaskStatus.RanToCompletion) 
         { 

          Task<int> completedTask = t; 
          var temp = _tempTaskList.ToList(); 
          //temp.Remove(t); 
          //_tempTaskList = temp.ToArray(); 
          noOfTasks++; 
          //Console.WriteLine(" Completed"); 
         } 
         else if (t != null && t.Status == TaskStatus.Faulted) 
         { 
          Console.WriteLine(" Failed"); 

         } 

        } 

        if (_tempTaskList.Length == 0) 
        { 
         IsAnyTaskPending = false; 
         Console.WriteLine("All {0} Tasks Done", noOfTasks); 
        } 

       } 

       IsWorkStarted = false; 
      } 
      catch(Exception e) 
      { 
       throw; 
      } 
     } 
    } 
} 
+1

Il semble que vous ne pouvez pas avoir deux écrivains qui écrivent exactement au même moment dans le journal. Vous devrez peut-être synchroniser l'accès (comme vous l'avez découvert) pour éviter les conflits. En passant, beaucoup de ce que vous faites peut être fait avec des suites (complet ou échoué, etc) et «Task.WhenAll». –

+0

Yeh semble comme ça ... Je ne veux pas faire Task.WhenAll parce que dans mon code de production, nous faisons quelque chose en surveillant le statut. – Zeus

Répondre

2

Le problème est que Logger.SetLogWriter est appelé pour chaque tâche. Le LogWriter interne est un singleton. Toutefois, lorsque vous appelez le SetLogWriterLogWriter interne en cours est disposé:

public static void SetLogWriter(LogWriter logWriter, bool throwIfSet = true) 
    { 
     Guard.ArgumentNotNull(logWriter, "logWriter"); 

     var currentWriter = writer; 
     if (currentWriter != null && throwIfSet) 
     { 
      throw new InvalidOperationException(Resources.ExceptionLogWriterAlreadySet); 
     } 

     writer = logWriter; 

     if (currentWriter != null) 
     { 
      currentWriter.Dispose(); 
     } 
    } 

Donc, chaque tâche est la disposition de la singleton LogWriter qui tire le tapis sous une autre tâche. La solution consiste à boostraper SetLogWriter une fois avant d'invoquer les tâches.

+0

Salut Randy, pouvez-vous expliquer plus loin. Que voulez-vous dire par bootstrap SetLogWriter? – Zeus

+0

Ceci est le code qui exécute l'amorçage: 'Logger.SetLogWriter (new LogWriterFactory(). Create(), false);'. Déplacez ce code au début de la méthode 'Start' au lieu de le placer dans le thread. –