2012-12-11 30 views
0

我有一個計時器應該以500ms的間隔運行x次。目前我的代碼看起來是這樣的:x間隔後取消定時器

var i = 0; 
var times = 10; 
timer = new System.Threading.Timer(_ => 
{ 
    if (timer == null || i >= times) 
     return; 

    Console.WriteLine("Run " + i); 

    if (i < times - 1) 
     i++; 
    else 
    { 
     timer.Dispose(); 
     timer = null; 
    } 
}, null, 500, 500); 

這是一個可靠的方法來取消計時器,如果我要確保只有一個被創建和定時器變量引用?

間隔的數量在運行時是可變的。

回答

2

看起來定時器的優化配置非常安全的。我會讓我和時間變量是私人的,而不是方法的一部分。這會創建更快的代碼。此外,計時器委託可能在不同線程上同時運行的可能性很小,請參閱http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx,因此我可能使用Interlocked.Increment方法。

也許是這樣的:

class Foo 
{ 
    volatile int runCount; 
    int maxRunCount; 
    Timer timer; 

    void RunFor(int max) 
    { 
    maxRunCount = max; 
    timer = new System.Threading.Timer(_ => 
    { 
     if (timer == null) return; 
     Console.WriteLine("Run " + runCount); 

     if (Interlocked.Increment(ref runCount) == maxRunCount) 
     { 
      timer.Dispose(); 
      timer = null; 
     } 
    }, null, 500, 500); 
    } 
} 

[編輯]

在代碼審查,我可能會拋出一個鎖周圍計時器的處置,防止競爭條件。

if (...) 
    { 
     lock(this) 
     { 
      if (timer != null) timer.Dispose(); 
      timer = null; 
     } 
    } 
+1

你有點過頭了。一旦調用Dispose,它不會再次觸發(我檢查了反彙編的代碼,確實確保'Dispose'以線程安全的方式執行)。 另外,如果您在開始時遞增runCount,然後執行Dispose檢查,則不會出現競爭狀況。 –

+0

@Johny,你是對的,因爲'Interlocked.Increment'應該處理任何競爭條件。我感覺最好在它周圍鎖定。談到多線程,我很謹慎。但感謝監督。 –

+0

我知道這種感覺! :)另一點是,你可以省略「timer = null」部分以及空檢查。 –

1

您應該使用System.Timers.Timer類,而不是...
它同時支持Stop()Start()方法。

短的例子:

System.Timers.Timer timer = new System.Timers.Timer(); 
var i = 0; 
var times = 10; 


public SetupTimer() 
{ 
    timer.Interval = 500; 
    timer.Elapsed += OnTimerElapsed; 
    timer.Start(); 
} 

private void OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) 
{ 
    // Logic 

    if (i > times) 
    { 
     timer.Stop(); 
    } 
}