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
parent
commit
38e37e96a5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 45
      src/Android/Avalonia.Android/AndroidThreadingInterface.cs
  2. 4
      src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs
  3. 48
      src/Avalonia.Headless/HeadlessPlatformThreadingInterface.cs

45
src/Android/Avalonia.Android/AndroidThreadingInterface.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();
}
}); });
} }

4
src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs

@ -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);
}); });
} }

48
src/Avalonia.Headless/HeadlessPlatformThreadingInterface.cs

@ -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;
}
}); });
} }

Loading…
Cancel
Save