2013-02-13 33 views
5

Tôi đang cố gắng sử dụng Timer để kích hoạt sự kiện gửi dữ liệu qua mạng. Tôi đã tạo một lớp đơn giản để gỡ lỗi. Về cơ bản tôi có một số List<string> Tôi muốn gửi. Tôi muốn những điều sau xảy ra:Đặt lại System.Timers.Timer để ngăn sự kiện đã trôi qua

  1. Add chuỗi List
  2. Bắt đầu Timer trong 10 giây
  3. Thêm chuỗi thứ hai để List trước Timer.Elapsed
  4. Restart Timer lại 10 giây.

Cho đến nay tôi có điều này:

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

Bất kỳ ý tưởng?

Trả lời

11

Bạn có thể sử dụng chức năng Stop ngay sau đó các Start chức năng để "khởi động lại" bộ đếm thời gian. Sử dụng điều đó bạn có thể tạo ra Timer khi lớp được tạo lần đầu tiên, kết nối sự kiện Đã trôi qua tại thời điểm đó và sau đó không làm gì ngoài việc gọi hai phương thức đó khi một mục được thêm vào. Nó sẽ khởi động hoặc khởi động lại, bộ hẹn giờ. Lưu ý rằng việc gọi Stop trên bộ hẹn giờ chưa được bắt đầu chỉ thực hiện không có gì, nó không ném ngoại lệ hoặc gây ra bất kỳ sự cố nào khác.

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

Lưu ý rằng thay vì sử dụng một List nó rất có thể là bạn muốn sử dụng một BlockingCollection<string> để thay thế. Điều này có một số lợi thế. Đầu tiên, các phương thức Log sẽ hoạt động nếu được gọi cùng một lúc từ nhiều luồng; cũng như nhiều nhật ký đồng thời có thể phá vỡ danh sách. Nó cũng có nghĩa là SendToServer có thể lấy các mục ra khỏi hàng đợi cùng lúc với các mục mới được thêm vào. Nếu bạn sử dụng List, bạn sẽ cần phải lock tất cả quyền truy cập vào danh sách (có thể không phải là vấn đề nhưng không đơn giản).

+0

Từ câu hỏi, tôi hiểu rằng anh ấy muốn tích lũy dữ liệu trong danh sách và gửi chúng một lần chỉ sau 10 giây kể từ lần bổ sung cuối cùng vào danh sách đã trôi qua. Anh ta muốn tránh SendToServer được gọi hai lần nếu anh ta thêm dữ liệu vào danh sách hai lần ba giây. Tôi có thể sai, nhưng đó là cách tôi đọc nó. –

+0

@zespri Đó chính là cách tôi đọc nó. Đó là chính xác những gì mã này. – Servy

+0

thậm chí sử dụng bộ đếm thời gian .. đây là ý tưởng tồi .. Không có khóa, không có hình thức đồng bộ hóa .. Bộ hẹn giờ là cách tồi tệ nhất để thực hiện việc này, anh ta nên xem xét lại cách giải quyết vấn đề này. –

-4

Những gì bạn đang triển khai hoàn toàn là cách sai để thực hiện việc này. Có một cái nhìn vào mô hình sản xuất tiêu dùng:

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

gì bạn đang cố gắng làm là rất thường được gọi là mô hình dataflow Consumer/Nhà sản xuất. Về cơ bản bạn có một cái gì đó tạo ra một danh sách các dữ liệu được gửi ở đâu đó, thay vì gửi nó mỗi khi một mục được thêm vào danh sách bạn muốn gửi chúng theo nhóm .. Vì vậy, bạn có một nhà sản xuất (mã đưa dữ liệu vào được gửi) và người tiêu dùng (mã gửi dữ liệu).

Thông thường vấn đề này được giải quyết bằng cách sinh ra một chuỗi theo dõi danh sách (thường là một hàng đợi) và gửi dữ liệu theo khoảng thời gian quy định, cách tốt nhất để làm điều này là sử dụng EventWaitHandle.

Dưới đây là một số mã rất đơn giản là một ví dụ

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

Liên kết của bạn hiển thị "Chủ đề này đã lỗi thời." và không chứa thông tin hữu ích. –

+0

Tôi không biết bạn đang nói gì hoặc trang nào được cho là nói với tôi – tedski

+0

ok Tôi sẽ chỉnh sửa và giải thích thêm ... –