【问题标题】:Timer intervals getting mixed up between threads线程之间的计时器间隔混淆
【发布时间】:2013-06-27 11:13:59
【问题描述】:

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

这是我的场景:

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

为 1 配置:

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

客户代码:A

时间间隔:5000

2 的配置:

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

客户代码:B

时间间隔: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;
    }
}

}

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

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

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

DoWork - 客户名称:1 27/06/2013 12:13:12

DoWork - 客户名称:2 27/06/2013 12:13:12

ClientName : 1 经过 27/06/2013 12:13:13

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

ClientName : 1 经过 27/06/2013 12:13:15

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

ClientName : 1 经过 27/06/2013 12:13:17

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

ClientName : 1 经过 27/06/2013 12:13:19

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

ClientName : 1 经过 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

我对使用计时器的线程概念非常陌生。如果有人建议如何分别设置每个线程中经过的计时器间隔,我将不胜感激。谢谢!

【问题讨论】:

  • 所有线程都使用同一个计时器!
  • 感谢您指出这一点。但结果中的时间间隔仍然不合适。

标签: c# multithreading timer


【解决方案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;
    }
}

【讨论】:

  • 第一个线程似乎以 5 秒的间隔工作。但是第二个线程以 2 秒的间隔工作(应该如此)并不总是 ThreadStart - ClientName :1 27/06/2013 13:40:11 ThreadStart - ClientName :2 27/06/2013 13:40:11 ClientName : 2 Elapsed 2013 年 6 月 27 日 13:40:13 客户名称:2 已用 2013 年 6 月 27 日 13:40:15 客户名称:1 已用 2013 年 6 月 27 日 13:40:16 客户名称:2 已用 2013 年 6 月 27 日 13:40 :21 //** 这里是 5 秒 ClientName : 1 Elapsed 27/06/2013 13:40:21 ClientName : 1 Elapsed 27/06/2013 13:40:26 ClientName : 2 Elapsed 27/06/2013 13: 40:31 //** 这里是 10 秒
  • 查看文档msdn.microsoft.com/en-us/library/…。由于 Elapsed-event 被推送到线程池,因此确切的执行时间可能会有所不同。
【解决方案2】:

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

课堂节目

{

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


}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-13
    • 2020-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-22
    • 2015-06-01
    相关资源
    最近更新 更多