0

I wanted to test if I can trigger an event using method working in a new task.

when I do this:

using System;
using System.Threading.Tasks;


namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {

            subscriber f = new subscriber();
        }

    }


    class subscriber
    {
        publisher x;
        public subscriber()
        {
            x = new publisher();
            x.ThresholdReached += c_ThresholdReached;
            x.method2();
        }

        static void c_ThresholdReached(object sender, EventArgs e)
        {
            Console.WriteLine("The threshold was reached.");
        }
    }



    class publisher
    {
        public event EventHandler ThresholdReached;


        public publisher()
        {
       
        }

        public void method1()
        {
            OnThresholdReached(EventArgs.Empty);
        }

        public void method2()
        {
            Task.Run(() => method1());

        }


        protected virtual void OnThresholdReached(EventArgs e)
        {
            EventHandler handler = ThresholdReached;
            handler?.Invoke(this, e);
        }

    }
}

The output is nothing!

However, when I do this:

using System;
using System.Threading.Tasks;


namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {

            subscriber f = new subscriber();
        }

    }


    class subscriber
    {
        publisher x;
        public subscriber()
        {
            x = new publisher();
            x.ThresholdReached += c_ThresholdReached;
            x.method2();
        }

        static void c_ThresholdReached(object sender, EventArgs e)
        {
            Console.WriteLine("The threshold was reached.");
        }
    }



    class publisher
    {
        public event EventHandler ThresholdReached;


        public publisher()
        {
       
        }

        public void method1()
        {
            OnThresholdReached(EventArgs.Empty);
        }

        public void method2()
        {
            //Here is the change
            method1();
            Task.Run(() => method1());

        }


        protected virtual void OnThresholdReached(EventArgs e)
        {
            EventHandler handler = ThresholdReached;
            handler?.Invoke(this, e);
        }

    }
}

the output is this:

The threshold was reached
The threshold was reached

this is strange! I could not understand why it prints twice.

However, I excepted it will not work with method1 is running in new task, because it will not be working in the same thread

could someone explain why? and is there a way to communicate a concurrent method with the parent thread?

thanks in advance

2 Answers2

1

As mentioned in comment, your code finishes before the task will run and pring anything. You should modify your code in async manner to await the task to finish

using System;
using System.Threading.Tasks;


namespace ConsoleApp2
{
    class Program
    {
        static async Task Main(string[] args)
        {
            subscriber f = new subscriber();
            await f.Test();
        }

    }


    class subscriber
    {
        publisher x;
        public subscriber()
        {
            x = new publisher();
            x.ThresholdReached += c_ThresholdReached;
        }
        
        public async Task Test()
        {
            await x.method2();
        }

        static void c_ThresholdReached(object sender, EventArgs e)
        {
            Console.WriteLine("The threshold was reached.");
        }
    }


    class publisher
    {
        public event EventHandler ThresholdReached;


        public publisher()
        {
       
        }

        public void method1()
        {
            OnThresholdReached(EventArgs.Empty);
        }

        public async Task method2()
        {
            await Task.Run(() => method1());
        }


        protected virtual void OnThresholdReached(EventArgs e)
        {
            EventHandler handler = ThresholdReached;
            handler?.Invoke(this, e);
        }

    }
}

As for your second snippet, that looks like the Task has time to run and pring while the main thread printing inside method1. Some times it will pring twice (if have enaught of time) or will print once (if Console.Write in main thread will finish before the task will run).

Additional note: please be aware that your event handler will be called not in main thread, but in the thread in which task is executed (typically, this will be a thread from a thread pool)

Serg
  • 3,454
  • 2
  • 13
  • 17
0

When you call Task.Run(...), the action inside Run() will be started in new thread.

In your first case you start the new thread with Task.Run(), but the program finishes and exits before it executes that the new thread. You can prevent the main thread from terminating by adding Console.Read() at the end of Main(). This way you can wait for the second thread to finish.

class Program
{
    static void Main(string[] args)
    {
        subscriber f = new subscriber();
        Console.Read();
    }

}

In your second case you will get two messages because of this:

public void method2()
{
    method1();
    Task.Run(() => method1());
}

This time since you are directly calling method1() you will for sure write the message once in the console. Since printing on the console (any IO in general) is relatively slow, the second thread (created by Task.Run()) will have time to execute, and print the message second time.

Another solution is to create the thread manually

public void method2()
{
    Thread t1 = new Thread(() => method1());
    t1.IsBackground = false;
    t1.Start();
}

The program will not exit until all foreground threads have finished. So when you set IsBackground = false;, the program will wait for that thread

Mitko Petrov
  • 311
  • 1
  • 4
  • 12