简体   繁体   中英

EventHandler is always null in C#

I'm writing a scheduler as a request for an exercise, so I can not use the windows's one.

The structure of my scheduler is almost complete, they're missing only a few secondary details.

As a request I need to use a main thread to control if there are tasks programmed in the time of execution, and if so, I have to start a secondary thread to execute the process. One of the requests is to use a limited number of threads, so I have a variable that counts the actual number of threads in execution. I want to use an event to signal to the main thread when a secondary thread is finished. I've searched a lot, here and in many other sites. Practically every site suggests the solution I've implemented, but in my case the EventHandler i've used is always null ... and I do not understand why. Could someone help me? Thanks a lot !!

Here is the code.

This is the class of the secondary thread:

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);
        }

    }
}

This is the class of the scheduler:

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;
    }*/
}

The problem is on the event ExecutionFinished in the class Thread_word, that is always null. It seems that my code is correct according to the researches I've done, but obviously is not. I have no more ideas of where the problem could be, so I hope someone can help me! Thanks!

You're calling LaunchCommandLineApp from the constructor; the EventHandler is null because you set it in the next line after new Thread_work(j) , which is too late because the constructor already executed.

First, don't call in the constructor:

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

Then call LaunchCommandLineApp after you set the delegate:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM