Как заблокировать таймер при обработке прошедшего события?
У меня есть таймер, который не должен обрабатывать обработчик прошедшего события в одно и то же время. Но обработка одного Истекшего события может помешать другим. Я реализовал нижеследующее решение, но что-то не так. мне кажется, что либо я должен использовать таймер по-другому, либо использовать другой объект в потоковом пространстве. Кажется, что таймер подходит лучше всего, потому что мне нужно периодически проверять статус, но иногда проверка займет больше времени, чем мой интервал. Это лучший способ приблизиться к этому?
// member variable
private static readonly object timerLock = new object();
private bool found = false;
// elsewhere
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed = Timer_OnElapsed;
timer.Start();
public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
lock(timerLock)
{
if (!found)
{
found = LookForItWhichMightTakeALongTime();
}
}
}
Ответы
Ответ 1
Вы можете установить AutoReset в значение false, а затем явно reset таймер после того, как вы его обработаете. Конечно, как вы справляетесь с этим, все зависит от того, как вы ожидаете, что таймер будет работать. Выполнение этого способа позволит вашему таймеру отклониться от фактического заданного интервала (как и при остановке и перезапуске). Ваш механизм позволит каждому интервалу срабатывать и обрабатываться, но это может привести к отставанию необработанных событий, которые обрабатываются сейчас, где рядом с истечением таймера, вызывающего вызов обработчика.
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed += Timer_OnElapsed;
timer.AutoReset = false;
timer.Start();
public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
if (!found)
{
found = LookForItWhichMightTakeALongTime();
}
timer.Start();
}
Ответ 2
Я обычно останавливаю таймер во время его обработки, вводим блок try/finally и возобновляю таймер, когда это делается.
Ответ 3
Если LookForItWhichMightTakeALongTime()
будет занимать много времени, я бы предложил не использовать System.Windows.Forms.Timer
, потому что это закроет ваш поток пользовательского интерфейса, и пользователь может убить ваше приложение, думая, что оно замерло.
Что вы можете использовать, это BackgroundWorker
(вместе с Timer
, если это необходимо).
public class MyForm : Form
{
private BackgroundWorker backgroundWorker = new BackgroundWorker();
public MyForm()
{
InitializeComponents();
backgroundWorker.DoWork += backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted +=
backgroundWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = LookForItWhichMightTakeALongTime();
}
private void backgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
found = e.Result as MyClass;
}
}
И вы можете позвонить RunWorkerAsync()
из любого места, где хотите, даже если вы хотите использовать Timer
. И просто убедитесь, что проверка BackgroundWorker
выполняется уже с момента вызова RunWorkerAsync()
при запуске вызовет исключение.
private void timer_Tick(object sender, EventArgs e)
{
if (!backgroundWorker.IsBusy)
backgroundWorker.RunWorkerAsync();
}
Ответ 4
timer.enabled = false
или
timer.stop();
и
timer.enabled = true
или
timer.start();
Ответ 5
Я использую System.Threading.Timer так
class Class1
{
static Timer timer = new Timer(DoSomething,null,TimeSpan.FromMinutes(1),TimeSpan.FromMinutes(1));
private static void DoSomething(object state)
{
timer = null; // stop timer
// do some long stuff here
timer = new Timer(DoSomething, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
}
}