Browse Source
Merge pull request #8702 from ili/avoid_lock_in_timer
Avoid lock in timers
pull/8742/head
Max Katz
4 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with
42 additions and
55 deletions
-
src/Android/Avalonia.Android/AndroidThreadingInterface.cs
-
src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs
-
src/Avalonia.Headless/HeadlessPlatformThreadingInterface.cs
|
|
@ -27,46 +27,33 @@ namespace Avalonia.Android |
|
|
{ |
|
|
{ |
|
|
if (interval.TotalMilliseconds < 10) |
|
|
if (interval.TotalMilliseconds < 10) |
|
|
interval = TimeSpan.FromMilliseconds(10); |
|
|
interval = TimeSpan.FromMilliseconds(10); |
|
|
object l = new object(); |
|
|
|
|
|
var stopped = false; |
|
|
var stopped = false; |
|
|
Timer timer = null; |
|
|
Timer timer = null; |
|
|
var scheduled = false; |
|
|
|
|
|
timer = new Timer(_ => |
|
|
timer = new Timer(_ => |
|
|
{ |
|
|
{ |
|
|
lock (l) |
|
|
if (stopped) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
EnsureInvokeOnMainThread(() => |
|
|
{ |
|
|
{ |
|
|
if (stopped) |
|
|
try |
|
|
{ |
|
|
{ |
|
|
timer.Dispose(); |
|
|
tick(); |
|
|
return; |
|
|
|
|
|
} |
|
|
} |
|
|
if (scheduled) |
|
|
finally |
|
|
return; |
|
|
|
|
|
scheduled = true; |
|
|
|
|
|
EnsureInvokeOnMainThread(() => |
|
|
|
|
|
{ |
|
|
{ |
|
|
try |
|
|
if (!stopped) |
|
|
{ |
|
|
timer.Change(interval, Timeout.InfiniteTimeSpan); |
|
|
tick(); |
|
|
} |
|
|
} |
|
|
}); |
|
|
finally |
|
|
}, |
|
|
{ |
|
|
null, interval, Timeout.InfiniteTimeSpan); |
|
|
lock (l) |
|
|
|
|
|
{ |
|
|
|
|
|
scheduled = false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
}, null, TimeSpan.Zero, interval); |
|
|
|
|
|
|
|
|
|
|
|
return Disposable.Create(() => |
|
|
return Disposable.Create(() => |
|
|
{ |
|
|
{ |
|
|
lock (l) |
|
|
stopped = true; |
|
|
{ |
|
|
timer.Dispose(); |
|
|
stopped = true; |
|
|
|
|
|
timer.Dispose(); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -43,7 +43,7 @@ namespace Avalonia.Controls.Platform |
|
|
_priority = priority; |
|
|
_priority = priority; |
|
|
_interval = interval; |
|
|
_interval = interval; |
|
|
_tick = tick; |
|
|
_tick = tick; |
|
|
_timer = new Timer(OnTimer, null, interval, TimeSpan.FromMilliseconds(-1)); |
|
|
_timer = new Timer(OnTimer, null, interval, Timeout.InfiniteTimeSpan); |
|
|
_handle = GCHandle.Alloc(_timer); |
|
|
_handle = GCHandle.Alloc(_timer); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -57,7 +57,7 @@ namespace Avalonia.Controls.Platform |
|
|
if (_timer == null) |
|
|
if (_timer == null) |
|
|
return; |
|
|
return; |
|
|
_tick(); |
|
|
_tick(); |
|
|
_timer?.Change(_interval, TimeSpan.FromMilliseconds(-1)); |
|
|
_timer?.Change(_interval, Timeout.InfiniteTimeSpan); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -36,35 +36,35 @@ namespace Avalonia.Headless |
|
|
|
|
|
|
|
|
public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick) |
|
|
public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick) |
|
|
{ |
|
|
{ |
|
|
var cancelled = false; |
|
|
if (interval.TotalMilliseconds < 10) |
|
|
var enqueued = false; |
|
|
interval = TimeSpan.FromMilliseconds(10); |
|
|
var l = new object(); |
|
|
|
|
|
var timer = new Timer(_ => |
|
|
var stopped = false; |
|
|
|
|
|
Timer timer = null; |
|
|
|
|
|
timer = new Timer(_ => |
|
|
{ |
|
|
{ |
|
|
lock (l) |
|
|
if (stopped) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
Dispatcher.UIThread.Post(() => |
|
|
{ |
|
|
{ |
|
|
if (cancelled || enqueued) |
|
|
try |
|
|
return; |
|
|
|
|
|
enqueued = true; |
|
|
|
|
|
Dispatcher.UIThread.Post(() => |
|
|
|
|
|
{ |
|
|
{ |
|
|
lock (l) |
|
|
tick(); |
|
|
{ |
|
|
} |
|
|
enqueued = false; |
|
|
finally |
|
|
if (cancelled) |
|
|
{ |
|
|
return; |
|
|
if (!stopped) |
|
|
tick(); |
|
|
timer.Change(interval, Timeout.InfiniteTimeSpan); |
|
|
} |
|
|
} |
|
|
}, priority); |
|
|
}); |
|
|
} |
|
|
}, |
|
|
}, null, interval, interval); |
|
|
null, interval, Timeout.InfiniteTimeSpan); |
|
|
|
|
|
|
|
|
return Disposable.Create(() => |
|
|
return Disposable.Create(() => |
|
|
{ |
|
|
{ |
|
|
lock (l) |
|
|
stopped = true; |
|
|
{ |
|
|
timer.Dispose(); |
|
|
timer.Dispose(); |
|
|
|
|
|
cancelled = true; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|