После прочтения ТАК я понимаю, что Thread.Sleep
это плохая идея .Вместо этого общий консенсус заключается в том, что задачи на стороне сервера должны использовать Timer
, threadpool
или, возможно, Join()
.
Одна статья упоминает о трудностях при утилизациитаймер.
В другой статье упоминается использование waitOne
Вопрос
Какой правильный подход использовать при запускедлительное задание, которое будет повторяться каждые 30 секунд, 1 минуту или 5 минут?Ограничение состоит в том, что ЕСЛИ предыдущий запуск этой задачи длиннее интервала (32 секунды или 7 минут), то я хочу, чтобы опция либо убивала этот предыдущий экземпляр, либо не выполняла новый экземпляр.
AВозможно, я намерен использовать олицетворение в этих потоках, используя WindowsImpersionationContext , P / Invoke LogonUserEX или DCOMShim при необходимости.
Я не уверен, какой подход и почему.
Возможный ответ 1
Этот пример выглядит простым, с минимальным беспорядком кода
// initially set to a "non-signaled" state, ie will block
// if inspected
private readonly AutoResetEvent _isStopping = new AutoResetEvent(false);
/// <summary>
/// from...
/// /1607526/system-timers-timer-threading-timer-protiv-potoka-s-whileloop-thread-sleep-dlya-periodicheskih-zadach#1607532
/// </summary>
public void SampleDelay1()
{
TimeSpan waitInterval = TimeSpan.FromMilliseconds(1000);
// will block for 'waitInterval', unless another thread,
// say a thread requesting termination, wakes you up. if
// no one signals you, WaitOne returns false, otherwise
// if someone signals WaitOne returns true
for (; !_isStopping.WaitOne(waitInterval); )
{
// do your thang!
}
}
Возможный ответ 2
В этом примере представлены аналогичные функции, но используются анонимные типы, которые могут быть недопустимы в компаниях, которые не допускают этого в своем стандарте кодирования.
/// <summary>
/// Disposable Timer instance from
/// /325414/sravnite-ispolzuya-thread-sleep-i-timer-dlya-otlozhennogo-vypolneniya
/// </summary>
class TimerStackOverFlow
{
// Created by Roy Feintuch 2009
// Basically we wrap a timer object in order to send itself as a context in order
// to dispose it after the cb invocation finished. This solves the problem of timer
// being GCed because going out of context
public static void DoOneTime(ThreadStart cb, TimeSpan dueTime)
{
var td = new TimerDisposer();
// Is the next object System.Timers, or System.Threading
var timer = new Timer(myTdToKill =>
{
try
{
cb();
}
catch (Exception ex)
{
Trace.WriteLine(string.Format("[DoOneTime] Error occured while invoking delegate. {0}", ex), "[OneTimer]");
}
finally
{
((TimerDisposer)myTdToKill).InternalTimer.Dispose();
}
},
td, dueTime, TimeSpan.FromMilliseconds(-1));
td.InternalTimer = timer;
}
}
class TimerDisposer
{
public Timer InternalTimer { get; set; }
}