views:

66

answers:

1

How do you make a event-driven program where the execution of the main flow is suspended whenever an event is raised and handled, until the event handler finishes?

I created the following program

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

namespace EventTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Timer t = new Timer(2000);
            t.Enabled = true;
            t.Elapsed += new ElapsedEventHandler(TimerHandler);
            for (int i = 0; i < 10000; i++)
            {
                for (int j = 0; j < 100000000; j++) ;
                Console.WriteLine(i);
            }
        }
        public static void TimerHandler(object source, EventArgs e)
        {
            Console.WriteLine("Event started");
            for (int i = 0; i < 5; i++)
            {
                for (int j = 0; j < 100000000; j++) ;
                Console.WriteLine("Event "+i);
            }
            Console.WriteLine("Event finished");
        }

    }
}

The main method is supposed to print sequential numbers, and an event is fired every 2 seconds. During the event handling, the program is supposed to print "Event started", "Event 1" to "Event 5", then "Event Finished", then returns.

I expected Main() flow to stop while TimerHandler() is called, however my output suggests that Main() and TimerHandler() both are run simultaneously

0
1
2
3
4
5
6
7
8
9
10
11
Event started
12
Event 0
13
Event 1
14
Event 2
15
Event 3
16
Event 4
Event finished
17
18
19
20
21
22
23
Event started
24
Event 0
25
Event 1
26
Event 2
27
Event 3
28
Event 4
Event finished
29
30
31
32
33

Is it possible to make the Main() method to stop while the event is handled?

+2  A: 

You're using System.Timers.Timer, which processes ticks on a background thread, typically using the thread pool.

As such, yes, it will run simultaneously with the rest of your Main code.

As for your second question, possible to get Main to stop, I need to know what the expected behavior is.

If you want an entire tick in TimerHandler to run together, pausing Main while it does so, a simple lock would suffice:

namespace EventTest
{
    class Program
    {
        static object _Lock = new object();

        static void Main(string[] args)
        {
            Timer t = new Timer(2000);
            t.Enabled = true;
            t.Elapsed += new ElapsedEventHandler(TimerHandler);
            for (int i = 0; i < 10000; i++)
            {
                for (int j = 0; j < 100000000; j++) ;
                lock (_Lock)
                    Console.WriteLine(i);
            }
        }
        public static void TimerHandler(object source, EventArgs e)
        {
            lock (_Lock)
            {
                Console.WriteLine("Event started");
                for (int i = 0; i < 5; i++)
                {
                    for (int j = 0; j < 100000000; j++) ;
                    Console.WriteLine("Event "+i);
                }
                Console.WriteLine("Event finished");
            }
        }
    }
}
Lasse V. Karlsen
is there any way to stop the Main() method while the handler is running?
Louis Rhys
Edited my answer.
Lasse V. Karlsen
@Lasse - correct me if i'm wrong, but with this approach won't you end up with a race condition, this only works because the handler grabs the lock before Main() can? Would you not be better off with a Manual/AutoResetEvent?
slugster
thank you.The expected behaviour is the Main() method is paused while TimerHandler is run. Your solution will work if we know which part of Main needs to be locked, am I correct?What if there is a lot of codes, and I want it to pause when there is an event being handled?
Louis Rhys
You can't do that, you need to explicitly block out pieces of the code with locks. And no, this will not create any race conditions.
Lasse V. Karlsen
@Lasse - sweet as, i just went back and re-read the @OPs requirement and your answer, i get it now :)
slugster