计时器间隔在线程之间混淆

时间:2013-06-27 11:14:00

标签: c# multithreading timer

我在带有C#的.net 2.0中的多线程应用程序上使用System.Timers。 每个线程应该为其计时器已用事件设置不同的时间间隔。

这是我的情景:

我有一个根文件夹说:D:// ThreadingDemo / Clients。现在,Clients文件夹可以包含n个文件夹。假设:1和2(在实际场景中等于客户端数量)。在每个文件夹中都有一个xml配置文件(具有客户端特定的详细信息)。

配置为1:

ApplicationName:客户端1的应用程序支持

ClientCode:A

TimeInterval:5000

配置2:

ApplicationName:客户端2的应用程序支持

ClientCode:B

TimeInterval:2000

现在我的应用程序创建了与客户端数量一样多的线程。在这种情况下,2个线程并在线程内设置一个时间间隔 线程1的间隔为5000毫秒,线程2的间隔为2000毫秒

下面是我工作的代码:

命名空间ConsoleApplication3

{

class Program

{

    static string location = "D:\\ThreadingDemo\\Clients\\";
    public static System.Timers.Timer emailTriggerTimer = new System.Timers.Timer();
    static Double timeinterval;

    static void Main(string[] args)
    {

        System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(location);
        Thread th;
        foreach (System.IO.DirectoryInfo g in dir.GetDirectories())
        {
            th = new Thread(() => DoWork(g.Name)); //** Passes CLIENT NAME to the method
            th.Name = g.Name;
            th.Start();
            Console.WriteLine(" ThreadStart - ClientName : " + g.Name + " " + DateTime.Now);
        }
        Console.ReadKey();
    }

    public static void DoWork(string fname)
    {

        emailTriggerTimer.Interval = GetsExecutionTimeFromConfigFile(); //** Gets Client specific FIRST EXECUTION TIME and converts to Time Interval
        emailTriggerTimer.Elapsed += new System.Timers.ElapsedEventHandler((sender, e) => emailTriggerTimer_Elapsed(sender, e, fname));
        emailTriggerTimer.Enabled = true;
        emailTriggerTimer.AutoReset = true;
        emailTriggerTimer.Start();

        Console.WriteLine(" DoWork - ClientName :" + fname + " " + DateTime.Now);
    }

    private static object emailTriggerTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e, string fname)
    {
        emailTriggerTimer.Stop();
        emailTriggerTimer.Enabled = false;

        Console.WriteLine(fname + " Elapsed "   + DateTime.Now);
        emailTriggerTimer.Interval = GetsTimeIntervalFromConfigFile(); //** Gets Client specific TIME INTERVAL

        emailTriggerTimer.Start();
        emailTriggerTimer.Enabled = true;
    }
}

}

我的代码肯定会搞砸定时器间隔并在两个线程上设置最后一个定时器间隔,即2000ms,这是下面的输出:

ThreadStart - ClientName:1 27/06/2013 12:13:12

ThreadStart - ClientName:2 27/06/2013 12:13:12

DoWork - ClientName:1 27/06/2013 12:13:12

DoWork - ClientName:2 27/06/2013 12:13:12

ClientName:1 Elapsed 27/06/2013 12:13:13

ClientName:2 Elapsed 27/06/2013 12:13:13

ClientName:1 Elapsed 27/06/2013 12:13:15

ClientName:2 Elapsed 27/06/2013 12:13:15

ClientName:1 Elapsed 27/06/2013 12:13:17

ClientName:2 Elapsed 27/06/2013 12:13:17

ClientName:1 Elapsed 27/06/2013 12:13:19

ClientName:2 Elapsed 27/06/2013 12:13:19

ClientName:1 Elapsed 27/06/2013 12:13:21

ClientName:2 Elapsed 27/06/2013 12:13:21

ClientName:1 Elapsed 27/06/2013 12:13:23

ClientName:2 Elapsed 27/06/2013 12:13:23

我很擅长使用计时器来处理概念。如果有人建议如何分别为每个线程中的过去设置定时器间隔,我将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:1)

由于您对所有线程使用单个计时器对象,因此每个线程的事件处理程序将添加到该单个计时器中。因此,当该单个计时器对象的间隔到期时,将执行所有事件处理程序。

解决方案是为每个单独的线程创建一个计时器对象。

像这样。

class Program {
    static string location = "D:\\ThreadingDemo\\Clients\\";
    static Double timeinterval;


    static void Main(string[] args) {
        System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(location);
        foreach (System.IO.DirectoryInfo g in dir.GetDirectories()) {
            var th = new Thread(() => DoWork(g.Name)); //** Passes CLIENT NAME to the method
            th.Name = g.Name;
            th.Start();
            Console.WriteLine(" ThreadStart - ClientName : " + g.Name + " " + DateTime.Now);
        }
        Console.ReadKey();
    }

    public static void DoWork(string fname) {
        var emailTriggerTimer = new System.Timers.Timer();
        emailTriggerTimer.Interval = GetsExecutionTimeFromConfigFile(); //** Gets Client specific FIRST EXECUTION TIME and converts to Time Interval
        emailTriggerTimer.Elapsed += new System.Timers.ElapsedEventHandler((sender, e) => emailTriggerTimer_Elapsed(sender, e, fname, emailTriggerTimer));
        emailTriggerTimer.Enabled = true;
        emailTriggerTimer.AutoReset = true;
        emailTriggerTimer.Start();

        Console.WriteLine(" DoWork - ClientName :" + fname + " " + DateTime.Now);
    }

    private static void emailTriggerTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e, string fname, System.Timers.Timer emailTriggerTimer) {
        emailTriggerTimer.Stop();
        emailTriggerTimer.Enabled = false;

        Console.WriteLine(fname + " Elapsed "   + DateTime.Now);
        emailTriggerTimer.Interval = GetsTimeIntervalFromConfigFile(); //** Gets Client specific TIME INTERVAL

        emailTriggerTimer.Start();
        emailTriggerTimer.Enabled = true;
    }
}

答案 1 :(得分:0)

这似乎对我有用。我通过一个简单的改变重新审视了这一点。第一次执行不是由计时器设置的,而是通过允许线程休眠来完成的。为计时器设置的间隔(在第一次执行之后)完美地工作。这是代码:

课程计划

{

    static string location = "D:\\ThreadingDemo\\Clients\\";
    static Double timeinterval;
    public static System.Timers.Timer emailTriggerTimer;
    static void Main(string[] args)
    {

        System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(location);
        Thread th;
        foreach (System.IO.DirectoryInfo g in dir.GetDirectories())
        {
            th = new Thread(() => DoWork(g.Name));
            th.Name = g.Name;
            th.Start();
            Console.WriteLine(" ThreadStart - ClientName :" + g.Name + " " + DateTime.Now);
        }
        Console.ReadKey();
    }

    public static void DoWork(string fname)
    {

        Thread.Sleep(Convert.ToInt32(GetsExecutionTimeFromConfigFile()));//** Gets Client specific FIRST EXECUTION TIME and converts to Time Interval           

        emailTriggerTimer  = new System.Timers.Timer();
        emailTriggerTimer.AutoReset = true;
        emailTriggerTimer.Elapsed += new System.Timers.ElapsedEventHandler((sender, e) => emailTriggerTimer_Elapsed(sender, e, fname));
        emailTriggerTimer.Interval =  GetsTimeIntervalFromConfigFile(); //** Gets Client specific TIME INTERVAL
        emailTriggerTimer.Enabled = true;

        emailTriggerTimer.Start();

        Console.WriteLine(" DoWork - ClientName :" + fname + " " + DateTime.Now);
    }

    private static void emailTriggerTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e, string fname)
    {

        Console.WriteLine("ClientName : " + fname + " Elapsed " + " " + DateTime.Now );
    }


}