6

I am trying to use the Timer to trigger an event to send data across the network. I created a simple class to debug. Basically I have a List<string> I'd like to send. I want the following to happen:

  1. Add string to List
  2. Start Timer for 10 seconds
  3. Add second string to List before Timer.Elapsed
  4. Restart Timer back at 10 seconds.

So far I have this:

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

Any ideas?

4

3 に答える 3

12

Stop関数の直後に関数を使用してStart、タイマーを「再起動」できます。これを使用してTimer、クラスが最初に作成されたときに を作成し、その時点で Elapsed イベントを接続し、アイテムが追加されたときにこれら 2 つのメソッドを呼び出すだけです。タイマーを開始または再起動します。まだ開始されていないタイマーを呼び出し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();
    }
}

Lista を使用するのではなく、代わりにa を使用する可能性が非常に高いことに注意してくださいBlockingCollection<string>。これにはいくつかの利点があります。まず、Logメソッドは複数のスレッドから同時に呼び出された場合に機能します。複数の同時ログがリストを壊す可能性があるためです。SendToServerまた、新しいアイテムが追加されると同時にキューからアイテムを取り出すことができることも意味します。a を使用するList場合は、リストへのすべてのアクセスが必要にlockなります (これは問題にはならないかもしれませんが、それほど簡単ではありません)。

于 2013-02-13T19:10:37.943 に答える
-5

あなたが実装しているのは、これを行うための完全に間違った方法です。消費者プロデューサーモデルを見てください:

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...

        }
    }
}
于 2013-02-13T19:09:23.257 に答える