簡體   English   中英

使用帶有Threading.Timer的鎖

[英]Using lock with Threading.Timer

我有一個Windows服務應用程序,它使用Threading.TimerTimerCallback以特定的間隔進行一些處理。 我需要一次將此處理代碼鎖定為僅1個線程。

因此,例如,啟動服務並觸發第一個回調並啟動線程並開始處理。 只要在下一次回調之前完成處理,這就可以正常工作。 所以說比如說處理比平常花費的時間稍長,並且在另一個線程正在處理時再次觸發TimerCallback,我需要讓該線程等到另一個線程完成。

這是我的代碼示例:

static Timer timer;
static object locker = new object();

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, 10000);
}

public void DoSomething()
{
      lock(locker)
      {
           // my processing code
      }
}

這是一種安全的方法嗎? 如果隊列變得相當大,會發生什么? 有更好的選擇嗎?

如果您可以使用它們之間的恆定間隔觸發事件(與以恆定間隔觸發它們的當前代碼相反),那么您可以在沒有句點的情況下啟動計時器,並且每次排隊新的回調時,例如

static Timer timer;

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, Timeout.Infinite);
}

public void DoSomething()
{
      try
      {
           // my processing code
      }
      finally
      {
          timer.Change(10000, Timeout.Infinite);
      }
}

此代碼告訴新創建的計時器立即觸發,僅一次。 在處理代碼中,它完成工作,然后告訴計時器在10秒內再次觸發,僅一次。 因為定時器現在不是定期觸發但是通過其回調方法重新啟動,所以回調保證是單線程的,沒有隊列。

如果你想保持一個恆定的間隔,那么它有點棘手,因為你必須決定如果處理開始花費的時間超過定時器間隔該怎么辦。 一種選擇是執行您當前正在執行的操作,但這實際上會導致大量排隊的線程和最終的線程池飢餓。 另一種選擇是,如果已經有一個回調,則簡單地丟棄回調,例如

static Timer timer;
static object locker = new object();

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, 10000);
}

public void DoSomething()
{
      if (Monitor.TryEnter(locker))
      {
           try
           {
               // my processing code
           }
           finally
           {
               Monitor.Exit(locker);
           }
      }
}

如果處理代碼執行時間超過10秒,最糟糕的情況是,每次調用一個新的回調時,你將浪費1個線程池線程(它們將在lock語句中等待)。 如果你采取所有線程池線程HttpWebRequest,ASP.NET,異步委托調用...將受到影響。

我要做的是立即安排第一次回調。 to be called every 10s: 然后,如果你真的需要每隔10秒調用一次

public void DoSomething ()
{
       DateTime start = DateTime.UtcNow;
       ...
       TimeSpan elapsed = (DateTime.UtcNow - start);
       int due_in = (int) (10000 - elapsed.TotalMilliseconds);
       if (due_in < 0)
           due_in = 0;
       timer.Change (due_in, Timeout.Infinite);
}

或者那條線上的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM