Del*_*ate 7 c# timer thread-safety
我有一个函数,我想每x秒调用一次,但我希望它是线程安全的.
我在创建计时器时可以设置此行为吗?(我不介意我使用哪个.NET计时器,我只是希望它是线程安全的).
我知道我可以在我的回调函数中实现锁,但我认为如果它在计时器级别会更优雅.
我的回调函数和环境与UI无关.
[编辑1] 我只是不希望我的回调函数中有多个线程.
[编辑2] 我想将锁定保持在计时器级别内,因为计时器负责何时调用我的回调,这里有一种特殊情况,当我不想调用我的回调函数时.所以我觉得什么时候打电话是计时器的责任.
Tim*_*oyd 18
我猜测,因为你的问题并不完全清楚,你想要确保你的计时器在处理回调时无法重新输入你的回调,而你想要在没有锁定的情况下这样做.您可以使用a来实现此目的,System.Timers.Timer并确保将该AutoReset属性设置为false.这将确保您必须手动触发每个间隔的计时器,从而防止任何重入:
public class NoLockTimer : IDisposable
{
private readonly Timer _timer;
public NoLockTimer()
{
_timer = new Timer { AutoReset = false, Interval = 1000 };
_timer.Elapsed += delegate
{
//Do some stuff
_timer.Start(); // <- Manual restart.
};
_timer.Start();
}
public void Dispose()
{
if (_timer != null)
{
_timer.Dispose();
}
}
}
Run Code Online (Sandbox Code Playgroud)
作为Tim Lloyd的解决方案的补充System.Timers.Timer,这里有一个解决方案,可以防止您想要使用的情况进行重入System.Threading.Timer.
TimeSpan DISABLED_TIME_SPAN = TimeSpan.FromMilliseconds(-1);
TimeSpan interval = TimeSpan.FromSeconds(1);
Timer timer = null; // assign null so we can access it inside the lambda
timer = new Timer(callback: state =>
{
doSomeWork();
try
{
timer.Change(interval, DISABLED_TIME_SPAN);
}
catch (ObjectDisposedException timerHasBeenDisposed)
{
}
}, state: null, dueTime: interval, period: DISABLED_TIME_SPAN);
Run Code Online (Sandbox Code Playgroud)
我相信你不想interval在回调中访问,但如果你想这样做很容易解决:把上面的内容放到一个NonReentrantTimer包装BCL Timer类的类中.然后,您将doSomeWork作为参数传递回调.这样一个类的一个例子:
public class NonReentrantTimer : IDisposable
{
private readonly TimerCallback _callback;
private readonly TimeSpan _period;
private readonly Timer _timer;
public NonReentrantTimer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
{
_callback = callback;
_period = period;
_timer = new Timer(Callback, state, dueTime, DISABLED_TIME_SPAN);
}
private void Callback(object state)
{
_callback(state);
try
{
_timer.Change(_period, DISABLED_TIME_SPAN);
}
catch (ObjectDisposedException timerHasBeenDisposed)
{
}
}
public void Dispose()
{
_timer.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)