1
0
mirror of https://github.com/DarthAffe/RGB.NET.git synced 2025-12-13 10:08:31 +00:00

Merge pull request #116 from DarthAffe/Fix/ThreadSafety

Fix/thread safety
This commit is contained in:
DarthAffe 2020-03-03 15:25:09 +01:00 committed by GitHub
commit 89810e4b1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 67 deletions

View File

@ -36,7 +36,7 @@ namespace RGB.NET.Core
#region Methods #region Methods
/// <inheritdoc /> /// <inheritdoc />
public abstract IEnumerable<Led> GetLeds(); public abstract IList<Led> GetLeds();
/// <inheritdoc /> /// <inheritdoc />
public virtual void OnAttach() public virtual void OnAttach()

View File

@ -25,7 +25,7 @@ namespace RGB.NET.Core
/// Gets a list containing all <see cref="Led"/> of this <see cref="ILedGroup"/>. /// Gets a list containing all <see cref="Led"/> of this <see cref="ILedGroup"/>.
/// </summary> /// </summary>
/// <returns>The list containing all <see cref="Led"/> of this <see cref="ILedGroup"/>.</returns> /// <returns>The list containing all <see cref="Led"/> of this <see cref="ILedGroup"/>.</returns>
IEnumerable<Led> GetLeds(); IList<Led> GetLeds();
/// <summary> /// <summary>
/// Called when the <see cref="ILedGroup"/> is attached to the <see cref="RGBSurface"/>. /// Called when the <see cref="ILedGroup"/> is attached to the <see cref="RGBSurface"/>.

View File

@ -38,7 +38,14 @@ namespace RGB.NET.Core
/// <summary> /// <summary>
/// Gets a readonly list containing all loaded <see cref="IRGBDevice"/>. /// Gets a readonly list containing all loaded <see cref="IRGBDevice"/>.
/// </summary> /// </summary>
public IEnumerable<IRGBDevice> Devices => new ReadOnlyCollection<IRGBDevice>(_devices); public IEnumerable<IRGBDevice> Devices
{
get
{
lock (_devices)
return new ReadOnlyCollection<IRGBDevice>(_devices);
}
}
/// <summary> /// <summary>
/// Gets a readonly list containing all registered <see cref="IUpdateTrigger"/>. /// Gets a readonly list containing all registered <see cref="IUpdateTrigger"/>.
@ -53,7 +60,14 @@ namespace RGB.NET.Core
/// <summary> /// <summary>
/// Gets a list of all <see cref="Led"/> on this <see cref="RGBSurface"/>. /// Gets a list of all <see cref="Led"/> on this <see cref="RGBSurface"/>.
/// </summary> /// </summary>
public IEnumerable<Led> Leds => _devices.SelectMany(x => x); public IEnumerable<Led> Leds
{
get
{
lock (_devices)
return _devices.SelectMany(x => x);
}
}
#endregion #endregion
@ -92,11 +106,12 @@ namespace RGB.NET.Core
bool updateDevices = customData["updateDevices"] as bool? ?? true; bool updateDevices = customData["updateDevices"] as bool? ?? true;
lock (_updateTriggers) lock (_updateTriggers)
lock (_devices)
{ {
OnUpdating(updateTrigger, customData); OnUpdating(updateTrigger, customData);
if (syncBack) if (syncBack)
foreach (IRGBDevice device in Devices) foreach (IRGBDevice device in _devices)
if (device.UpdateMode.HasFlag(DeviceUpdateMode.SyncBack) && device.DeviceInfo.SupportsSyncBack) if (device.UpdateMode.HasFlag(DeviceUpdateMode.SyncBack) && device.DeviceInfo.SupportsSyncBack)
try { device.SyncBack(); } try { device.SyncBack(); }
catch (Exception ex) { OnException(ex); } catch (Exception ex) { OnException(ex); }
@ -111,7 +126,7 @@ namespace RGB.NET.Core
} }
if (updateDevices) if (updateDevices)
foreach (IRGBDevice device in Devices) foreach (IRGBDevice device in _devices)
if (!device.UpdateMode.HasFlag(DeviceUpdateMode.NoUpdate)) if (!device.UpdateMode.HasFlag(DeviceUpdateMode.NoUpdate))
try { device.Update(flushLeds); } try { device.Update(flushLeds); }
catch (Exception ex) { OnException(ex); } catch (Exception ex) { OnException(ex); }
@ -128,13 +143,12 @@ namespace RGB.NET.Core
/// <inheritdoc /> /// <inheritdoc />
public void Dispose() public void Dispose()
{ {
//if (_updateTokenSource?.IsCancellationRequested == false) lock (_devices)
// _updateTokenSource.Cancel();
foreach (IRGBDevice device in _devices) foreach (IRGBDevice device in _devices)
try { device.Dispose(); } try { device.Dispose(); }
catch { /* We do what we can */} catch { /* We do what we can */}
lock (_deviceProvider)
foreach (IRGBDeviceProvider deviceProvider in _deviceProvider) foreach (IRGBDeviceProvider deviceProvider in _deviceProvider)
try { deviceProvider.Dispose(); } try { deviceProvider.Dispose(); }
catch { /* We do what we can */} catch { /* We do what we can */}
@ -223,10 +237,13 @@ namespace RGB.NET.Core
} }
private void UpdateSurfaceRectangle() private void UpdateSurfaceRectangle()
{
lock (_devices)
{ {
Rectangle devicesRectangle = new Rectangle(_devices.Select(d => d.DeviceRectangle)); Rectangle devicesRectangle = new Rectangle(_devices.Select(d => d.DeviceRectangle));
SurfaceRectangle = SurfaceRectangle.SetSize(new Size(devicesRectangle.Location.X + devicesRectangle.Size.Width, devicesRectangle.Location.Y + devicesRectangle.Size.Height)); SurfaceRectangle = SurfaceRectangle.SetSize(new Size(devicesRectangle.Location.X + devicesRectangle.Size.Width, devicesRectangle.Location.Y + devicesRectangle.Size.Height));
} }
}
/// <summary> /// <summary>
/// Gets all devices of a specific type. /// Gets all devices of a specific type.
@ -235,7 +252,10 @@ namespace RGB.NET.Core
/// <returns>A list of devices with the specified type.</returns> /// <returns>A list of devices with the specified type.</returns>
public IList<T> GetDevices<T>() public IList<T> GetDevices<T>()
where T : class where T : class
=> new ReadOnlyCollection<T>(_devices.Select(x => x as T).Where(x => x != null).ToList()); {
lock (_devices)
return new ReadOnlyCollection<T>(_devices.Select(x => x as T).Where(x => x != null).ToList());
}
/// <summary> /// <summary>
/// Gets all devices of the specified <see cref="RGBDeviceType"/>. /// Gets all devices of the specified <see cref="RGBDeviceType"/>.
@ -243,7 +263,10 @@ namespace RGB.NET.Core
/// <param name="deviceType">The <see cref="RGBDeviceType"/> of the devices to get.</param> /// <param name="deviceType">The <see cref="RGBDeviceType"/> of the devices to get.</param>
/// <returns>a list of devices matching the specified <see cref="RGBDeviceType"/>.</returns> /// <returns>a list of devices matching the specified <see cref="RGBDeviceType"/>.</returns>
public IList<IRGBDevice> GetDevices(RGBDeviceType deviceType) public IList<IRGBDevice> GetDevices(RGBDeviceType deviceType)
=> new ReadOnlyCollection<IRGBDevice>(_devices.Where(d => deviceType.HasFlag(d.DeviceInfo.DeviceType)).ToList()); {
lock (_devices)
return new ReadOnlyCollection<IRGBDevice>(_devices.Where(d => deviceType.HasFlag(d.DeviceInfo.DeviceType)).ToList());
}
/// <summary> /// <summary>
/// Registers the provided <see cref="IUpdateTrigger"/>. /// Registers the provided <see cref="IUpdateTrigger"/>.

View File

@ -28,6 +28,8 @@ namespace RGB.NET.Core
/// <param name="exclusiveAccessIfPossible">Specifies whether the application should request exclusive access of possible or not.</param> /// <param name="exclusiveAccessIfPossible">Specifies whether the application should request exclusive access of possible or not.</param>
/// <param name="throwExceptions">Specifies whether exception during the initialization sequence should be thrown or not.</param> /// <param name="throwExceptions">Specifies whether exception during the initialization sequence should be thrown or not.</param>
public void LoadDevices(IRGBDeviceProvider deviceProvider, RGBDeviceType loadFilter = RGBDeviceType.All, bool exclusiveAccessIfPossible = false, bool throwExceptions = false) public void LoadDevices(IRGBDeviceProvider deviceProvider, RGBDeviceType loadFilter = RGBDeviceType.All, bool exclusiveAccessIfPossible = false, bool throwExceptions = false)
{
lock (_deviceProvider)
{ {
if (_deviceProvider.Contains(deviceProvider) || _deviceProvider.Any(x => x.GetType() == deviceProvider.GetType())) return; if (_deviceProvider.Contains(deviceProvider) || _deviceProvider.Any(x => x.GetType() == deviceProvider.GetType())) return;
@ -35,7 +37,7 @@ namespace RGB.NET.Core
if (deviceProvider.IsInitialized || deviceProvider.Initialize(loadFilter, exclusiveAccessIfPossible, throwExceptions)) if (deviceProvider.IsInitialized || deviceProvider.Initialize(loadFilter, exclusiveAccessIfPossible, throwExceptions))
{ {
_deviceProvider.Add(deviceProvider); _deviceProvider.Add(deviceProvider);
lock (_devices)
foreach (IRGBDevice device in deviceProvider.Devices) foreach (IRGBDevice device in deviceProvider.Devices)
{ {
if (_devices.Contains(device)) continue; if (_devices.Contains(device)) continue;
@ -53,6 +55,7 @@ namespace RGB.NET.Core
SurfaceLayoutChanged?.Invoke(new SurfaceLayoutChangedEventArgs(addedDevices, true, false)); SurfaceLayoutChanged?.Invoke(new SurfaceLayoutChangedEventArgs(addedDevices, true, false));
} }
} }
}
/// <summary> /// <summary>
/// Automatically aligns all devices to prevent overlaps. /// Automatically aligns all devices to prevent overlaps.

View File

@ -92,6 +92,7 @@ namespace RGB.NET.Groups
{ {
if (leds == null) return; if (leds == null) return;
lock (GroupLeds)
foreach (Led led in leds) foreach (Led led in leds)
if ((led != null) && !ContainsLed(led)) if ((led != null) && !ContainsLed(led))
GroupLeds.Add(led); GroupLeds.Add(led);
@ -111,6 +112,7 @@ namespace RGB.NET.Groups
{ {
if (leds == null) return; if (leds == null) return;
lock (GroupLeds)
foreach (Led led in leds) foreach (Led led in leds)
if (led != null) if (led != null)
GroupLeds.Remove(led); GroupLeds.Remove(led);
@ -121,7 +123,11 @@ namespace RGB.NET.Groups
/// </summary> /// </summary>
/// <param name="led">The LED which should be checked.</param> /// <param name="led">The LED which should be checked.</param>
/// <returns><c>true</c> if the LED is contained by this ledgroup; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the LED is contained by this ledgroup; otherwise, <c>false</c>.</returns>
public bool ContainsLed(Led led) => (led != null) && GroupLeds.Contains(led); public bool ContainsLed(Led led)
{
lock (GroupLeds)
return (led != null) && GroupLeds.Contains(led);
}
/// <summary> /// <summary>
/// Merges the <see cref="Led"/> from the given ledgroup in this ledgroup. /// Merges the <see cref="Led"/> from the given ledgroup in this ledgroup.
@ -129,6 +135,7 @@ namespace RGB.NET.Groups
/// <param name="groupToMerge">The ledgroup to merge.</param> /// <param name="groupToMerge">The ledgroup to merge.</param>
public void MergeLeds(ILedGroup groupToMerge) public void MergeLeds(ILedGroup groupToMerge)
{ {
lock (GroupLeds)
foreach (Led led in groupToMerge.GetLeds()) foreach (Led led in groupToMerge.GetLeds())
if (!GroupLeds.Contains(led)) if (!GroupLeds.Contains(led))
GroupLeds.Add(led); GroupLeds.Add(led);
@ -139,7 +146,11 @@ namespace RGB.NET.Groups
/// Gets a list containing the <see cref="T:RGB.NET.Core.Led" /> from this group. /// Gets a list containing the <see cref="T:RGB.NET.Core.Led" /> from this group.
/// </summary> /// </summary>
/// <returns>The list containing the <see cref="T:RGB.NET.Core.Led" />.</returns> /// <returns>The list containing the <see cref="T:RGB.NET.Core.Led" />.</returns>
public override IEnumerable<Led> GetLeds() => GroupLeds; public override IList<Led> GetLeds()
{
lock (GroupLeds)
return new List<Led>(GroupLeds);
}
#endregion #endregion
} }

View File

@ -105,7 +105,7 @@ namespace RGB.NET.Groups
/// Gets a list containing all <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.RectangleLedGroup" />. /// Gets a list containing all <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.RectangleLedGroup" />.
/// </summary> /// </summary>
/// <returns>The list containing all <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.RectangleLedGroup" />.</returns> /// <returns>The list containing all <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.RectangleLedGroup" />.</returns>
public override IEnumerable<Led> GetLeds() => _ledCache ??= RGBSurface.Instance.Leds.Where(led => led.AbsoluteLedRectangle.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList(); public override IList<Led> GetLeds() => _ledCache ??= RGBSurface.Instance.Leds.Where(led => led.AbsoluteLedRectangle.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList();
private void InvalidateCache() => _ledCache = null; private void InvalidateCache() => _ledCache = null;