2013-02-13 123 views
5

我试图使用Timer来触发事件以通过网络发送数据。我创建了一个简单的类来调试。基本上我有一个List<string>我想发送。我想下面的情况发生:重置System.Timers.Timer以防止Elapsed事件

  1. 添加字符串List
  2. 开始Timer 10秒
  3. 添加第二个字符串ListTimer.Elapsed
  4. 重启Timer回到10秒。

到目前为止,我有这样的:

public static List<string> list; 
public static Timer timer; 
public static bool isWiredUp = false; 

public static void Log(string value) { 
    if (list == null) list = new List<string>(); 
    list.Add(value); 

    //this does not reset the timer, elapsed still happens 10s after #1 
    if (timer != null) { 
     timer = null; 
    } 

    timer = new Timer(10000); 
    timer.Start(); 
    timer.Enabled = true; 
    timer.AutoReset = false; 

    if (!isWiredUp) { 
     timer.Elapsed += new ElapsedEventHandler(SendToServer); 
     isWiredUp = true; 
    } 
} 

static void SendToServer(object sender, ElapsedEventArgs e) { 
    timer.Enabled = false; 
    timer.Stop(); 
} 

任何想法?

回答

11

可以使用Stop功能由Start功能为“重启”定时器紧随其后。使用该功能,您可以在首次创建类时创建Timer,然后在此时连线Elapsed事件,然后在添加项时调用这两种方法。它将启动或重新启动计时器。请注意,在尚未启动的计时器上调用Stop只会不做任何事情,它不会抛出异常或导致任何其他问题。

public class Foo 
{ 
    public static List<string> list; 
    public static Timer timer; 
    static Foo() 
    { 
     list = new List<string>(); 
     timer = new Timer(10000); 
     timer.Enabled = true; 
     timer.AutoReset = false; 
     timer.Elapsed += SendToServer; 
    } 

    public static void Log(string value) 
    { 
     list.Add(value); 
     timer.Stop(); 
     timer.Start(); 
    } 

    static void SendToServer(object sender, ElapsedEventArgs e) 
    { 
     //TODO send data to server 

     //AutoReset is false, so neither of these are needed 
     //timer.Enabled = false; 
     //timer.Stop(); 
    } 
} 

注意,而不是使用List要使用BlockingCollection<string>相反,它是非常有可能的。这有几个优点。首先,如果多线程同时调用Log方法将会工作;因为多个并发日志可能会破坏列表。这也意味着SendToServer可以在添加新项目的同时将项目从队列中取出。如果您使用List,则需要lock才能访问列表(这可能不是问题,但不是那么简单)。

+0

从这个问题我明白,他想积累列表中的数据,并且只有自上次添加到列表已经过去10秒后才发送一次。他希望避免SendToServer被两次调用两次,如果他将数据添加到列表两次相隔三秒。我可能是错的,但是我就是这么读的。 – 2013-02-13 19:17:24

+0

@zespri这正是我阅读它的方式。这正是这个代码所做的。 – Servy 2013-02-13 19:20:02

+0

即使使用计时器..这是一个坏主意..没有锁定,没有同步的形式..计时器是这样做绝对最糟糕的方式,他应该重新考虑他是如何解决这个问题的。 – 2013-02-13 19:21:51

-4

你正在执行的是完全错误的做法。看一看消费者生产模式:

http://msdn.microsoft.com/en-us/library/hh228601.aspx

你所试图做的是很通常被称为生产者/消费者数据流模型。从本质上讲,您可以生成一些要发送到某个地方的数据列表,而不是每次将某个项目添加到要发送给它们的列表中时发送。因此,您有一个生产者(代码将数据被发送)和消费者(发送数据的代码)。

通常这个问题是通过产生一个观察列表的线程(通常是一个队列)并以特定的时间间隔发送数据来解决的,最好的方法是使用EventWaitHandle。

下面是一些非常简单的代码为例

class ServerStuff 
{ 
    public void Init() 
    { 
     datatosend = new List<string>(); 
        exitrequest = new EventWaitHandle(false, EventResetMode.ManualReset); //This wait handle will signal the consumer thread to exit 
     Thread t = new Thread(new ThreadStart(_RunThread)); 
     t.Start(); // Start the consumer thread... 
    } 

    public void Stop() 
    { 
     exitrequest.Set(); 
    } 

    List<string> datatosend; 
    EventWaitHandle exitrequest; 

    public void AddItem(string item) 
    { 
     lock (((ICollection)datatosend).SyncRoot) 
      datatosend.Add(item); 
    } 

    private void RunThread() 
    { 
     while (exitrequest.WaitOne(10 * 1000)) //wait 10 seconds between sending data, or wake up immediatly to exit request 
     { 
      string[] tosend; 
      lock (((ICollection)datatosend).SyncRoot) 
      { 
       tosend = datatosend.ToArray(); 
       datatosend.Clear(); 
      } 

      //Send the data to Sever here... 

     } 
    } 
} 
+0

您的链接显示“此主题已过时”。并且不包含有用的信息。 – 2013-02-13 19:14:40

+0

我不知道你在说什么或者该页面应该告诉我什么 – tedski 2013-02-13 19:26:29

+0

好的我会编辑和解释更多... – 2013-02-13 19:27:00