2017-06-20 1 views
0

J'écris un planificateur comme une demande pour un exercice, donc je ne peux pas utiliser celui de Windows.EventHandler est toujours null dans C#

La structure de mon planificateur est presque complète, il ne manque que quelques détails secondaires.

En tant que requête, j'ai besoin d'utiliser un thread principal pour contrôler si des tâches sont programmées au moment de l'exécution, et si c'est le cas, je dois démarrer un thread secondaire pour exécuter le processus. Une des demandes est d'utiliser un nombre limité de threads, donc j'ai une variable qui compte le nombre réel de threads en cours d'exécution. Je veux utiliser un événement pour signaler au thread principal quand un thread secondaire est fini. J'ai beaucoup cherché, ici et dans de nombreux autres sites. Pratiquement chaque site suggère la solution que j'ai implémentée, mais dans mon cas, le EventHandler que j'ai utilisé est toujours nul ... et je ne comprends pas pourquoi. Quelqu'un pourrait-il m'aider? Merci beaucoup !!

Voici le code.

C'est la classe du fil secondaire:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Diagnostics; 

namespace scheduler 
{ 


    public delegate void EventHandler(object sender, EventArgs e); 

    public class Thread_work 
    { 

     public event EventHandler ExecutionFinished; 

     Job job; 

     public Thread_work(Job j) 
     { 
      job = j; 
      LaunchCommandLineApp(); 
     } 

     public void LaunchCommandLineApp() 
     { 
      // Use ProcessStartInfo class 
      ProcessStartInfo startInfo = new ProcessStartInfo(); 
      startInfo.CreateNoWindow = false; 
      startInfo.UseShellExecute = false; 
      startInfo.FileName = job.process; 
      startInfo.WindowStyle = ProcessWindowStyle.Hidden; 
      var count = job.args.Count(c => c == ';'); 
      startInfo.Arguments = "-f "; 
      while (count > 1) 
      { 
       startInfo.Arguments += job.args.Substring(0, job.args.IndexOf(';', 0)); 
       job.args = job.args.Substring(job.args.IndexOf(';', 0) + 1, job.args.Length - 1); 
       count--; 
      } 
      if (count == 1) startInfo.Arguments += job.args.Substring(0, job.args.IndexOf(';', 0)); 

      try 
      { 
       // Start the process with the info we specified. 
       // Call WaitForExit and then the using statement will close. 
       using (Process exeProcess = Process.Start(startInfo)) 
       { 
        exeProcess.WaitForExit(); 
        InvokeExecutionFinished(new EventArgs()); 
       } 
      } 
      catch 
      { 
       // Log error. 
      } 



     } 

     protected virtual void InvokeExecutionFinished(EventArgs e) 
     { 
      if (ExecutionFinished != null) 
       ExecutionFinished(this, e); 
     } 

    } 
} 

Ceci est la classe du programmateur:

using System; 
using System.Collections.Generic; 
using System.Collections.Concurrent; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Diagnostics; 
using System.Linq; 
using System.Text; 

using System.Runtime.InteropServices; 


namespace scheduler 
{ 

    /// <summary>Custom TaskScheduler that processes work items in batches, where 
    /// each batch is processed by a ThreadPool thread, in parallel.</summary> 
    /// <remarks> 
    /// This is used as the default scheduler in several places in this solution, by, 
    /// for example, calling it directly in <see cref="TaskExtensions.ForEachAsync"/>, 
    /// or by accessing the relevant property of the static <see cref="TaskSchedulers"/> 
    /// class.</remarks> 
    public class ParallelTaskScheduler 
    { 

     public event EventHandler ExecutionFinished; 

     public bool stop_scheduler = false; 

     public int maxDegreeOfParallelism, active_thread; 

     public LinkedList<Job> jobs = new LinkedList<Job>(); 

     public ParallelTaskScheduler(int maxDegreeOfParallelism) 
     { 
      if (maxDegreeOfParallelism < 1) 
       throw new ArgumentOutOfRangeException("maxDegreeOfParallelism"); 

      this.maxDegreeOfParallelism = maxDegreeOfParallelism; 
     } 

     public ParallelTaskScheduler() : this(Environment.ProcessorCount) { } 


     public void QueueJob(Job task) 
     { 

      lock (jobs) jobs.AddLast(task); 

     } 

     private void MainThread() { 

      DateTime start, stop, now; 
      now = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, 00); 

      while (!stop_scheduler) 
      { 
       start = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 00); 
       now = now.AddMinutes(1); 
       stop = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 00); 

       foreach (Job j in jobs) 
       { 

        if (!j.mutex && j.date <= stop && j.date >= start) 
        { 
         if (active_thread < maxDegreeOfParallelism) 
         { 
          //Avvia thread esecuzione 
          j.mutex = true; 
          Thread_work th = new Thread_work(j); 
          th.ExecutionFinished += new EventHandler(this.th_executionFinished); 
          active_thread++; 
          //Al termine controlla se ricorrente 
         } 

        } 
       } 



       Thread.Sleep(20000); 
      } 

     } 

     private void th_executionFinished(object sender, EventArgs e) { 
      active_thread--;    
     } 

     void Connect() { 

     } 

     /// <summary>Runs the work on the ThreadPool.</summary> 
     /// <remarks> 
     /// This TaskScheduler is similar to the <see cref="LimitedConcurrencyLevelTaskScheduler"/> 
     /// sample implementation, until it reaches this method. At this point, rather than pulling 
     /// one Task at a time from the list, up to maxDegreeOfParallelism Tasks are pulled, and run 
     /// on a single ThreadPool thread in parallel.</remarks> 
     public void RunTasks() 
     { 
      active_thread = 0; 
      stop_scheduler = false; 
      Task.Factory.StartNew(MainThread); 
     } 


     public void StopTasks() 
     { 

      stop_scheduler = true; 

     } 
    } 

/* [StructLayout(LayoutKind.Explicit)] 
    public class OverlapEvents 
    { 
     [FieldOffset(0)] 
     public Thread_work Source; 

     [FieldOffset(0)] 
     public ParallelTaskScheduler Target; 
    }*/ 
} 

Le problème est l'événement ExecutionFinished dans la classe Thread_word, qui est toujours nul. Il semble que mon code soit correct selon les recherches que j'ai faites, mais ce n'est évidemment pas le cas. Je n'ai plus d'idée d'où le problème pourrait être, alors j'espère que quelqu'un peut m'aider! Merci!

Répondre

2

Vous appelez LaunchCommandLineApp à partir du constructeur; le EventHandler est null car vous le définissez dans la ligne suivante après new Thread_work(j), ce qui est trop tard car le constructeur a déjà été exécuté.

Tout d'abord, ne pas appeler dans le constructeur:

public Thread_work(Job j) 
{ 
    job = j; 
} 

Ensuite, appelez LaunchCommandLineApp après avoir défini le délégué:

Thread_work th = new Thread_work(j); 
th.ExecutionFinished += new EventHandler(this.th_executionFinished); 
th.LaunchCommandLineApp();