Saji Ren
Saji Ren

Reputation: 115

About Threads Being Used in the Event Calling in C#

Below is the codes I used to learn the Event Calling in C#, and the situation of Threads Being Used in it. I have several questions when using it:

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

namespace EventSample1
{
    public class MyTimerClass
    {
        public event EventHandler MyElapsed;
        //----
        private void OnOneSecond(object source, EventArgs args)
        {
            if (MyElapsed != null)
            {
                MyElapsed(source, args);
            }
        }
        //----
        private System.Timers.Timer MyPrivateTimer; 
        //----
        public MyTimerClass()
        {
            MyPrivateTimer = new System.Timers.Timer();
            MyPrivateTimer.Elapsed += OnOneSecond;
            //----
            MyPrivateTimer.Interval = 1000;             
            MyPrivateTimer.Enabled = true;
        }
     }
    //----
    class classA
    {
        public void TimerHandlerA(object source, EventArgs args)
        {
            Console.WriteLine("{0} class A handler called! at thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
        }
    }
    class classB
    {
        public static void TimerHandlerB(object source, EventArgs args)
        {
            Console.WriteLine("{0} class B handler called! at thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
        }
    }
    //----
    class Program
    {
        static void Main()
        {
            Console.WriteLine("Main thread on {0}", Thread.CurrentThread.ManagedThreadId);
            classA ca = new classA();
            MyTimerClass mc = new MyTimerClass();
            //----
            mc.MyElapsed += ca.TimerHandlerA;
            mc.MyElapsed += classB.TimerHandlerB;
            //----
            Thread.Sleep(2250);
        }
    }
}

the results is like this: enter image description here

It shows that when mc.Elapsed being called, the main thread open another (invoke?) thread to perform the two EventHandler (TimerEventHandler A and B).

My Question 1. is that:

Why the main thread be labeled as No.1, but the new invoked thread be labeled as No.4? Then, what’s No.2 and No.3 thread? What do they do?


Then I changed my codes in the main(), to let the main thread sleep from 2.25s’ to 5.25s’,

Thread.Sleep(5250);

and I got different result (another thread being invoked ):

enter image description here

My Question 2. is that:

Is the number of threads being used totally decided by the system? Is it what people called “thread pools” to do that?


After that, I insert another line before the Thread.Sleep() to see what happen?

//----
mc.MyElapsed += ca.TimerHandlerA;
mc.MyElapsed += classB.TimerHandlerB;
Console.ReadLine();
//----
Thread.Sleep(2250);

The reason I do this is:

As I understanding, when the event myElapsed be called, A and B will be called. Before they being called, the program will use a new thread to perform the codes in TimerEventHandler A and B. And the main thread will soon get back to the readline() line and wait for us to input. Just like when we use Thread.Sleep(), the main thread just come back to the Thread.Sleep() and after 2.25s' to close the program running!

But the result is NOT like what we think, the TimerEventHandler A and B just be called again and again......like the main thread will never come to readline()! enter image description here

I just use different line in the same position, why the result is so different?

I think this may refer to some details in threads, but My book does not talk much about threads using in C#, could anyone recommend another good book for self-learning?

Thanks in advance!

Upvotes: 2

Views: 442

Answers (2)

Sir Rufo
Sir Rufo

Reputation: 19096

Why the main thread be labeled as No.1, but the new invoked thread be labeled as No.4? Then, what’s No.2 and No.3 thread? What do they do?

Do not care about the thread id.

  • Each thread has a unique id
  • System.Timers.Timer will call the timer event inside of a thread (and it can be any thread except the main thread)
  • System.Timers.Timer can use as many threads as it needs to do its job

So we can only rely on that the event will be called and the calling thread will have a different id than the main thread.

Is the number of threads being used totally decided by the system? Is it what people called “thread pools” to do that?

Yes, it is up to the implementation of System.Timers.Timer how the timer event is called. We do not really know if there is a thread pool involved, but does it really matters? As long as the instance behaves as documented/expected I do not care about the implementation.

If I do care about the implementation I just have a look at the sources to see what is happening under the hood.

... like the main thread will never come to Console.ReadLine()!

Well the main thread will reach that line for sure. But what does Console.ReadLine() really do?

It is waiting for an input from then user and will continue when the user press ENTER. So until you press ENTER the main thread is blocked. But all other threads are still running and will call the events which will output some text to console.

To prove this we just add some lines:

mc.MyElapsed += ca.TimerHandlerA;
mc.MyElapsed += classB.TimerHandlerB;

Console.WriteLine( "I am waiting for your input!" );
Console.ReadLine();
Console.WriteLine( "Thank you!" );

Thread.Sleep(2250);

Console.WriteLine( "Finished." );
Main thread on 1
I am waiting for your input!
2016-7-12 7:53:40 class A handler called! at thread 4
2016-7-12 7:53:40 class B handler called! at thread 4
2016-7-12 7:53:41 class A handler called! at thread 4
2016-7-12 7:53:41 class B handler called! at thread 4

and it will continue until you hit the ENTER key. And when you hit you should see the events are still called during the Thread.Sleep(2250).

2016-7-12 7:53:50 class A handler called! at thread 4
2016-7-12 7:53:50 class B handler called! at thread 4
Thank you!
2016-7-12 7:53:51 class A handler called! at thread 4
2016-7-12 7:53:51 class B handler called! at thread 4
2016-7-12 7:53:52 class A handler called! at thread 4
2016-7-12 7:53:52 class B handler called! at thread 4
Finished.

could anyone recommend another good book for self-learning?

No, that kind of questions are off topic here on SO.

Upvotes: 1

Phil Blackburn
Phil Blackburn

Reputation: 1067

I agree with the other comments, the question is too broad to cover is a concise answer. I suggest you check out this link: http://www.albahari.com/threading/ It covers a lot of detail and may well have the answers for this and many other questions that are running through your mind.

In general I think you're worrying too much about the precise detail of what is happening under the hood. Yes, its is good to understand how it all ties together but, as for the actual value assigned to the thread ID, this not significant. The system will manage the thread allocation for you and since the execution order and running time of each thread is non-deterministic, you will not be able to infer any order of execution from the value of the ThreadID itself. Although I believe threadID=1 is always the main thread - I personally wouldn't rely on that always being the case in the future. When you get a little deeper into threading, what will discover the more important aspects of synchronisation two or more threads using locking, latching, and semaphores. This is the correct way to control and/or keep track of the order of execution and for these, knowing the ThreadID is not important.

Upvotes: 0

Related Questions